kea-1.1.0/0000775000175000017500000000000012772742656007276 500000000000000kea-1.1.0/Makefile.in0000664000175000017500000010457212772742613011265 00000000000000# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = . DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/configure $(am__configure_deps) \ $(srcdir)/config.h.in $(srcdir)/dns++.pc.in $(dist_doc_DATA) \ $(pkginclude_HEADERS) AUTHORS COPYING ChangeLog INSTALL README \ compile config.guess config.sub install-sh missing ltmain.sh ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4macros/ax_boost_for_kea.m4 \ $(top_srcdir)/m4macros/ax_isc_rpath.m4 \ $(top_srcdir)/m4macros/libtool.m4 \ $(top_srcdir)/m4macros/ltoptions.m4 \ $(top_srcdir)/m4macros/ltsugar.m4 \ $(top_srcdir)/m4macros/ltversion.m4 \ $(top_srcdir)/m4macros/lt~obsolete.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ configure.lineno config.status.lineno mkinstalldirs = $(install_sh) -d CONFIG_HEADER = config.h CONFIG_CLEAN_FILES = dns++.pc CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ install-exec-recursive install-html-recursive \ install-info-recursive install-pdf-recursive \ install-ps-recursive install-recursive installcheck-recursive \ installdirs-recursive pdf-recursive ps-recursive \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgconfigdir)" \ "$(DESTDIR)$(pkgincludedir)" DATA = $(dist_doc_DATA) $(pkgconfig_DATA) HEADERS = $(pkginclude_HEADERS) RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ cscope distdir dist dist-all distcheck am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) \ $(LISP)config.h.in # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags CSCOPE = cscope DIST_SUBDIRS = $(SUBDIRS) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) distdir = $(PACKAGE)-$(VERSION) top_distdir = $(distdir) am__remove_distdir = \ if test -d "$(distdir)"; then \ find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \ && rm -rf "$(distdir)" \ || { sleep 5 && rm -rf "$(distdir)"; }; \ else :; fi am__post_remove_distdir = $(am__remove_distdir) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" DIST_ARCHIVES = $(distdir).tar.gz GZIP_ENV = --best DIST_TARGETS = dist-gzip distuninstallcheck_listfiles = find . -type f -print am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \ | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$' distcleancheck_listfiles = find . -type f -print ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ASCIIDOC = @ASCIIDOC@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BOOST_INCLUDES = @BOOST_INCLUDES@ BOOST_LIBS = @BOOST_LIBS@ BOTAN_TOOL = @BOTAN_TOOL@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CQL_CPPFLAGS = @CQL_CPPFLAGS@ CQL_LIBS = @CQL_LIBS@ CRYPTO_CFLAGS = @CRYPTO_CFLAGS@ CRYPTO_INCLUDES = @CRYPTO_INCLUDES@ CRYPTO_LDFLAGS = @CRYPTO_LDFLAGS@ CRYPTO_LIBS = @CRYPTO_LIBS@ CRYPTO_PACKAGE = @CRYPTO_PACKAGE@ CRYPTO_RPATH = @CRYPTO_RPATH@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DBLATEX = @DBLATEX@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DISTCHECK_BOOST_CONFIGURE_FLAG = @DISTCHECK_BOOST_CONFIGURE_FLAG@ DISTCHECK_CRYPTO_CONFIGURE_FLAG = @DISTCHECK_CRYPTO_CONFIGURE_FLAG@ DISTCHECK_GTEST_CONFIGURE_FLAG = @DISTCHECK_GTEST_CONFIGURE_FLAG@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ ELINKS = @ELINKS@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GENHTML = @GENHTML@ GREP = @GREP@ GTEST_CONFIG = @GTEST_CONFIG@ GTEST_INCLUDES = @GTEST_INCLUDES@ GTEST_LDADD = @GTEST_LDADD@ GTEST_LDFLAGS = @GTEST_LDFLAGS@ GTEST_SOURCE = @GTEST_SOURCE@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ KEA_CXXFLAGS = @KEA_CXXFLAGS@ LCOV = @LCOV@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LEXLIB = @LEXLIB@ LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LOG4CPLUS_INCLUDES = @LOG4CPLUS_INCLUDES@ LOG4CPLUS_LIBS = @LOG4CPLUS_LIBS@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ MYSQL_LIBS = @MYSQL_LIBS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PERL = @PERL@ PGSQL_CPPFLAGS = @PGSQL_CPPFLAGS@ PGSQL_LIBS = @PGSQL_LIBS@ PKG_CONFIG = @PKG_CONFIG@ PLANTUML = @PLANTUML@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SEP = @SEP@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ USE_LCOV = @USE_LCOV@ VALGRIND = @VALGRIND@ VERSION = @VERSION@ WARNING_GCC_44_STRICT_ALIASING_CFLAG = @WARNING_GCC_44_STRICT_ALIASING_CFLAG@ XSLTPROC = @XSLTPROC@ YACC = @YACC@ YFLAGS = @YFLAGS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ ACLOCAL_AMFLAGS = -I m4macros ${ACLOCAL_FLAGS} # ^^^^^^^^ This has to be the first line and cannot come later in this # Makefile.am due to some bork in some versions of autotools. SUBDIRS = compatcheck tools doc . ext src m4macros DISTCLEANFILES = config.report # When running distcheck target, do not install the configurations # Use same --with-gtest flag if set # Keep the crypto backend config # Keep the Boost configuration which becomes sensible DISTCHECK_CONFIGURE_FLAGS = --disable-install-configurations \ $(DISTCHECK_GTEST_CONFIGURE_FLAG) \ $(DISTCHECK_CRYPTO_CONFIGURE_FLAG) \ $(DISTCHECK_BOOST_CONFIGURE_FLAG) dist_doc_DATA = AUTHORS COPYING ChangeLog README #### include external sources in the distributed tarball: EXTRA_DIST = tools/path_replacer.sh tools/mk_cfgrpt.sh \ ext/coroutine/coroutine.h pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = dns++.pc CLEANFILES = $(abs_top_builddir)/logger_lockfile # config.h may be included by headers supplied for building user-written # hooks libraries, so we need to include it in the distribution. pkginclude_HEADERS = config.h all: config.h $(MAKE) $(AM_MAKEFLAGS) all-recursive .SUFFIXES: am--refresh: Makefile @: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ echo ' cd $(srcdir) && $(AUTOMAKE) --foreign'; \ $(am__cd) $(srcdir) && $(AUTOMAKE) --foreign \ && exit 0; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ echo ' $(SHELL) ./config.status'; \ $(SHELL) ./config.status;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) $(SHELL) ./config.status --recheck $(top_srcdir)/configure: $(am__configure_deps) $(am__cd) $(srcdir) && $(AUTOCONF) $(ACLOCAL_M4): $(am__aclocal_m4_deps) $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) $(am__aclocal_m4_deps): config.h: stamp-h1 @test -f $@ || rm -f stamp-h1 @test -f $@ || $(MAKE) $(AM_MAKEFLAGS) stamp-h1 stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status @rm -f stamp-h1 cd $(top_builddir) && $(SHELL) ./config.status config.h $(srcdir)/config.h.in: $(am__configure_deps) ($(am__cd) $(top_srcdir) && $(AUTOHEADER)) rm -f stamp-h1 touch $@ distclean-hdr: -rm -f config.h stamp-h1 dns++.pc: $(top_builddir)/config.status $(srcdir)/dns++.pc.in cd $(top_builddir) && $(SHELL) ./config.status $@ mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs distclean-libtool: -rm -f libtool config.lt install-dist_docDATA: $(dist_doc_DATA) @$(NORMAL_INSTALL) @list='$(dist_doc_DATA)'; test -n "$(docdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(docdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(docdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(docdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(docdir)" || exit $$?; \ done uninstall-dist_docDATA: @$(NORMAL_UNINSTALL) @list='$(dist_doc_DATA)'; test -n "$(docdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(docdir)'; $(am__uninstall_files_from_dir) install-pkgconfigDATA: $(pkgconfig_DATA) @$(NORMAL_INSTALL) @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(pkgconfigdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(pkgconfigdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgconfigdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgconfigdir)" || exit $$?; \ done uninstall-pkgconfigDATA: @$(NORMAL_UNINSTALL) @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(pkgconfigdir)'; $(am__uninstall_files_from_dir) install-pkgincludeHEADERS: $(pkginclude_HEADERS) @$(NORMAL_INSTALL) @list='$(pkginclude_HEADERS)'; test -n "$(pkgincludedir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(pkgincludedir)'"; \ $(MKDIR_P) "$(DESTDIR)$(pkgincludedir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(pkgincludedir)'"; \ $(INSTALL_HEADER) $$files "$(DESTDIR)$(pkgincludedir)" || exit $$?; \ done uninstall-pkgincludeHEADERS: @$(NORMAL_UNINSTALL) @list='$(pkginclude_HEADERS)'; test -n "$(pkgincludedir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(pkgincludedir)'; $(am__uninstall_files_from_dir) # This directory's subdirectories are mostly independent; you can cd # into them and run 'make' without going through this Makefile. # To change the values of 'make' variables: instead of editing Makefiles, # (1) if the variable is set in 'config.status', edit 'config.status' # (which will cause the Makefiles to be regenerated when you run 'make'); # (2) otherwise, pass the desired values on the 'make' command line. $(am__recursive_targets): @fail=; \ if $(am__make_keepgoing); then \ failcom='fail=yes'; \ else \ failcom='exit 1'; \ fi; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-recursive CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscope: cscope.files test ! -s cscope.files \ || $(CSCOPE) -b -q $(AM_CSCOPEFLAGS) $(CSCOPEFLAGS) -i cscope.files $(CSCOPE_ARGS) clean-cscope: -rm -f cscope.files cscope.files: clean-cscope cscopelist cscopelist: cscopelist-recursive cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags -rm -f cscope.out cscope.in.out cscope.po.out cscope.files distdir: $(DISTFILES) $(am__remove_distdir) test -d "$(distdir)" || mkdir "$(distdir)" @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done -test -n "$(am__skip_mode_fix)" \ || find "$(distdir)" -type d ! -perm -755 \ -exec chmod u+rwx,go+rx {} \; -o \ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ || chmod -R a+r "$(distdir)" dist-gzip: distdir tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz $(am__post_remove_distdir) dist-bzip2: distdir tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2 $(am__post_remove_distdir) dist-lzip: distdir tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz $(am__post_remove_distdir) dist-xz: distdir tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz $(am__post_remove_distdir) dist-tarZ: distdir @echo WARNING: "Support for shar distribution archives is" \ "deprecated." >&2 @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z $(am__post_remove_distdir) dist-shar: distdir @echo WARNING: "Support for distribution archives compressed with" \ "legacy program 'compress' is deprecated." >&2 @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz $(am__post_remove_distdir) dist-zip: distdir -rm -f $(distdir).zip zip -rq $(distdir).zip $(distdir) $(am__post_remove_distdir) dist dist-all: $(MAKE) $(AM_MAKEFLAGS) $(DIST_TARGETS) am__post_remove_distdir='@:' $(am__post_remove_distdir) # This target untars the dist file and tries a VPATH configuration. Then # it guarantees that the distribution is self-contained by making another # tarfile. distcheck: dist case '$(DIST_ARCHIVES)' in \ *.tar.gz*) \ GZIP=$(GZIP_ENV) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\ *.tar.bz2*) \ bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\ *.tar.lz*) \ lzip -dc $(distdir).tar.lz | $(am__untar) ;;\ *.tar.xz*) \ xz -dc $(distdir).tar.xz | $(am__untar) ;;\ *.tar.Z*) \ uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ *.shar.gz*) \ GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\ *.zip*) \ unzip $(distdir).zip ;;\ esac chmod -R a-w $(distdir) chmod u+w $(distdir) mkdir $(distdir)/_build $(distdir)/_inst chmod a-w $(distdir) test -d $(distdir)/_build || exit 0; \ dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ && am__cwd=`pwd` \ && $(am__cd) $(distdir)/_build \ && ../configure \ $(AM_DISTCHECK_CONFIGURE_FLAGS) \ $(DISTCHECK_CONFIGURE_FLAGS) \ --srcdir=.. --prefix="$$dc_install_base" \ && $(MAKE) $(AM_MAKEFLAGS) \ && $(MAKE) $(AM_MAKEFLAGS) dvi \ && $(MAKE) $(AM_MAKEFLAGS) check \ && $(MAKE) $(AM_MAKEFLAGS) install \ && $(MAKE) $(AM_MAKEFLAGS) installcheck \ && $(MAKE) $(AM_MAKEFLAGS) uninstall \ && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ distuninstallcheck \ && chmod -R a-w "$$dc_install_base" \ && ({ \ (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ } || { rm -rf "$$dc_destdir"; exit 1; }) \ && rm -rf "$$dc_destdir" \ && $(MAKE) $(AM_MAKEFLAGS) dist \ && rm -rf $(DIST_ARCHIVES) \ && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \ && cd "$$am__cwd" \ || exit 1 $(am__post_remove_distdir) @(echo "$(distdir) archives ready for distribution: "; \ list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' distuninstallcheck: @test -n '$(distuninstallcheck_dir)' || { \ echo 'ERROR: trying to run $@ with an empty' \ '$$(distuninstallcheck_dir)' >&2; \ exit 1; \ }; \ $(am__cd) '$(distuninstallcheck_dir)' || { \ echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \ exit 1; \ }; \ test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \ || { echo "ERROR: files left after uninstall:" ; \ if test -n "$(DESTDIR)"; then \ echo " (check DESTDIR support)"; \ fi ; \ $(distuninstallcheck_listfiles) ; \ exit 1; } >&2 distcleancheck: distclean @if test '$(srcdir)' = . ; then \ echo "ERROR: distcleancheck can only run from a VPATH build" ; \ exit 1 ; \ fi @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ || { echo "ERROR: files left in build directory after distclean:" ; \ $(distcleancheck_listfiles) ; \ exit 1; } >&2 check-am: all-am check: check-recursive all-am: Makefile $(DATA) $(HEADERS) config.h installdirs: installdirs-recursive installdirs-am: for dir in "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgconfigdir)" "$(DESTDIR)$(pkgincludedir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-recursive clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-recursive -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -f Makefile distclean-am: clean-am distclean-generic distclean-hdr \ distclean-libtool distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-dist_docDATA install-pkgconfigDATA \ install-pkgincludeHEADERS install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: @$(NORMAL_INSTALL) $(MAKE) $(AM_MAKEFLAGS) install-exec-hook install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -rf $(top_srcdir)/autom4te.cache -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: uninstall-dist_docDATA uninstall-pkgconfigDATA \ uninstall-pkgincludeHEADERS .MAKE: $(am__recursive_targets) all install-am install-exec-am \ install-strip .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \ am--refresh check check-am clean clean-cscope clean-generic \ clean-libtool cscope cscopelist-am ctags ctags-am dist \ dist-all dist-bzip2 dist-gzip dist-lzip dist-shar dist-tarZ \ dist-xz dist-zip distcheck distclean distclean-generic \ distclean-hdr distclean-libtool distclean-tags distcleancheck \ distdir distuninstallcheck dvi dvi-am html html-am info \ info-am install install-am install-data install-data-am \ install-dist_docDATA install-dvi install-dvi-am install-exec \ install-exec-am install-exec-hook install-html install-html-am \ install-info install-info-am install-man install-pdf \ install-pdf-am install-pkgconfigDATA install-pkgincludeHEADERS \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs installdirs-am maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-dist_docDATA uninstall-pkgconfigDATA \ uninstall-pkgincludeHEADERS .PHONY: check-valgrind check-valgrind-suppress check-valgrind: @HAVE_VALGRIND_TRUE@ @VALGRIND_COMMAND="$(VALGRIND) -q --gen-suppressions=all --track-origins=yes --num-callers=48 --leak-check=full --fullpath-after=" \ @HAVE_VALGRIND_TRUE@ make -C $(abs_top_builddir) check @HAVE_VALGRIND_FALSE@ @echo "*** Valgrind is required for check-valgrind ***"; exit 1; check-valgrind-suppress: @HAVE_VALGRIND_TRUE@ @VALGRIND_COMMAND="$(VALGRIND) -q --gen-suppressions=all --track-origins=yes --error-exitcode=1 --suppressions=$(abs_top_srcdir)/src/valgrind-suppressions --suppressions=$(abs_top_srcdir)/src/valgrind-suppressions.revisit --num-callers=48 --leak-check=full --fullpath-after=" \ @HAVE_VALGRIND_TRUE@ make -C $(abs_top_builddir) check @HAVE_VALGRIND_FALSE@ @echo "*** Valgrind is required for check-valgrind-suppress ***"; exit 1; clean-cpp-coverage: @if [ $(USE_LCOV) = yes ] ; then \ $(LCOV) --directory . --zerocounters; \ rm -rf $(abs_top_srcdir)/coverage-cpp-html/; \ else \ echo "C++ code coverage not enabled at configuration time." ; \ echo "Use: ./configure --with-lcov" ; \ fi perform-coverage: check report-cpp-coverage: @if [ $(USE_LCOV) = yes ] ; then \ $(LCOV) --capture --directory . --output-file all.info ; \ $(LCOV) --remove all.info \ c++/4.4\*/\* \ c++/4.4\*/backward/\* \ c++/4.4\*/bits/\* \ c++/4.4\*/ext/\* \ c++/4.4\*/\*-\*/bits/\* \ boost/\* \ if HAVE_BOTAN botan/\* \ endif ext/coroutine/\* \ gtest/\* \ include/\* \ log4cplus/\* \ if HAVE_OPENSSL openssl/\* \ endif unittests/\* \ \*_unittests.cc \ \*_unittest.cc \ \*_unittests.h \ --output report.info ; \ sed -e "s|$(abs_top_srcdir)|$(abs_top_builddir)|g" < report.info > report.info.2 ; \ $(GENHTML) --legend -o $(abs_top_builddir)/coverage-cpp-html report.info.2 ; \ echo "Generated C++ Code Coverage report in HTML at $(abs_top_builddir)/coverage-cpp-html" ; \ else \ echo "C++ code coverage not enabled at configuration time." ; \ echo "Use: ./configure --with-lcov" ; \ fi # for c++ test coverage coverage: clean-coverage perform-coverage report-coverage clean-coverage: clean-cpp-coverage report-coverage: report-cpp-coverage # for static C++ check using cppcheck (when available) cppcheck: cppcheck -I./src/lib -I./src/bin --enable=all --suppressions \ src/cppcheck-suppress.lst --inline-suppr \ --quiet --error-exitcode=1 \ --template '{file}:{line}: check_fail: {message} ({severity},{id})' \ src # These steps are necessary during installation install-exec-hook: mkdir -p $(DESTDIR)${localstatedir}/log/ mkdir -p $(DESTDIR)${localstatedir}/run/${PACKAGE_NAME} # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: kea-1.1.0/missing0000755000175000017500000001533012772742613010606 00000000000000#! /bin/sh # Common wrapper for a few potentially missing GNU programs. scriptversion=2013-10-28.13; # UTC # Copyright (C) 1996-2013 Free Software Foundation, Inc. # Originally written by Fran,cois Pinard , 1996. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. if test $# -eq 0; then echo 1>&2 "Try '$0 --help' for more information" exit 1 fi case $1 in --is-lightweight) # Used by our autoconf macros to check whether the available missing # script is modern enough. exit 0 ;; --run) # Back-compat with the calling convention used by older automake. shift ;; -h|--h|--he|--hel|--help) echo "\ $0 [OPTION]... PROGRAM [ARGUMENT]... Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due to PROGRAM being missing or too old. Options: -h, --help display this help and exit -v, --version output version information and exit Supported PROGRAM values: aclocal autoconf autoheader autom4te automake makeinfo bison yacc flex lex help2man Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and 'g' are ignored when checking the name. Send bug reports to ." exit $? ;; -v|--v|--ve|--ver|--vers|--versi|--versio|--version) echo "missing $scriptversion (GNU Automake)" exit $? ;; -*) echo 1>&2 "$0: unknown '$1' option" echo 1>&2 "Try '$0 --help' for more information" exit 1 ;; esac # Run the given program, remember its exit status. "$@"; st=$? # If it succeeded, we are done. test $st -eq 0 && exit 0 # Also exit now if we it failed (or wasn't found), and '--version' was # passed; such an option is passed most likely to detect whether the # program is present and works. case $2 in --version|--help) exit $st;; esac # Exit code 63 means version mismatch. This often happens when the user # tries to use an ancient version of a tool on a file that requires a # minimum version. if test $st -eq 63; then msg="probably too old" elif test $st -eq 127; then # Program was missing. msg="missing on your system" else # Program was found and executed, but failed. Give up. exit $st fi perl_URL=http://www.perl.org/ flex_URL=http://flex.sourceforge.net/ gnu_software_URL=http://www.gnu.org/software program_details () { case $1 in aclocal|automake) echo "The '$1' program is part of the GNU Automake package:" echo "<$gnu_software_URL/automake>" echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:" echo "<$gnu_software_URL/autoconf>" echo "<$gnu_software_URL/m4/>" echo "<$perl_URL>" ;; autoconf|autom4te|autoheader) echo "The '$1' program is part of the GNU Autoconf package:" echo "<$gnu_software_URL/autoconf/>" echo "It also requires GNU m4 and Perl in order to run:" echo "<$gnu_software_URL/m4/>" echo "<$perl_URL>" ;; esac } give_advice () { # Normalize program name to check for. normalized_program=`echo "$1" | sed ' s/^gnu-//; t s/^gnu//; t s/^g//; t'` printf '%s\n' "'$1' is $msg." configure_deps="'configure.ac' or m4 files included by 'configure.ac'" case $normalized_program in autoconf*) echo "You should only need it if you modified 'configure.ac'," echo "or m4 files included by it." program_details 'autoconf' ;; autoheader*) echo "You should only need it if you modified 'acconfig.h' or" echo "$configure_deps." program_details 'autoheader' ;; automake*) echo "You should only need it if you modified 'Makefile.am' or" echo "$configure_deps." program_details 'automake' ;; aclocal*) echo "You should only need it if you modified 'acinclude.m4' or" echo "$configure_deps." program_details 'aclocal' ;; autom4te*) echo "You might have modified some maintainer files that require" echo "the 'autom4te' program to be rebuilt." program_details 'autom4te' ;; bison*|yacc*) echo "You should only need it if you modified a '.y' file." echo "You may want to install the GNU Bison package:" echo "<$gnu_software_URL/bison/>" ;; lex*|flex*) echo "You should only need it if you modified a '.l' file." echo "You may want to install the Fast Lexical Analyzer package:" echo "<$flex_URL>" ;; help2man*) echo "You should only need it if you modified a dependency" \ "of a man page." echo "You may want to install the GNU Help2man package:" echo "<$gnu_software_URL/help2man/>" ;; makeinfo*) echo "You should only need it if you modified a '.texi' file, or" echo "any other file indirectly affecting the aspect of the manual." echo "You might want to install the Texinfo package:" echo "<$gnu_software_URL/texinfo/>" echo "The spurious makeinfo call might also be the consequence of" echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might" echo "want to install GNU make:" echo "<$gnu_software_URL/make/>" ;; *) echo "You might have modified some files without having the proper" echo "tools for further handling them. Check the 'README' file, it" echo "often tells you about the needed prerequisites for installing" echo "this package. You may also peek at any GNU archive site, in" echo "case some other package contains this missing '$1' program." ;; esac } give_advice "$1" | sed -e '1s/^/WARNING: /' \ -e '2,$s/^/ /' >&2 # Propagate the correct exit status (expected to be 127 for a program # not found, 63 for a program that failed due to version mismatch). exit $st # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: kea-1.1.0/config.h.in0000664000175000017500000001145212772742612011234 00000000000000/* config.h.in. Generated from configure.ac by autoheader. */ /* config.h inclusion marker */ #undef CONFIG_H_WAS_INCLUDED /* Enable low-performing debugging facilities? */ #undef ENABLE_DEBUG /* Check logger messages? */ #undef ENABLE_LOGGER_CHECKS /* Extended Kea version */ #undef EXTENDED_VERSION /* Does this platform have some undefined pthreads behavior? */ #undef HAS_UNDEFINED_PTHREAD_BEHAVIOR /* Define to 1 if you have the header file. */ #undef HAVE_BOOST_ASIO_HPP /* Define to 1 if you have the header file. */ #undef HAVE_BOOST_ASIO_IP_ADDRESS_HPP /* Define to 1 if you have the header file. */ #undef HAVE_BOOST_BIND_HPP /* Define to 1 if you have the header file. */ #undef HAVE_BOOST_DATE_TIME_POSIX_TIME_POSIX_TIME_TYPES_HPP /* Define to 1 if you have the header file. */ #undef HAVE_BOOST_FOREACH_HPP /* Define to 1 if you have the header file. */ #undef HAVE_BOOST_FUNCTION_HPP /* Define to 1 if you have the header file. */ #undef HAVE_BOOST_INTERPROCESS_SYNC_INTERPROCESS_UPGRADABLE_MUTEX_HPP /* Define to 1 if you have the header file. */ #undef HAVE_BOOST_SHARED_PTR_HPP /* Define to 1 if you have the header file. */ #undef HAVE_BOOST_SYSTEM_ERROR_CODE_HPP /* Define to 1 if you have the header file. */ #undef HAVE_BOTAN_BOTAN_H /* Define to 1 if getsockopt(IPV6_USE_MIN_MTU) does not work */ #undef HAVE_BROKEN_GET_IPV6_USE_MIN_MTU /* CQL is present */ #undef HAVE_CQL /* Define to 1 if you have the header file. */ #undef HAVE_DLFCN_H /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_LOG4CPLUS_LOGGER_H /* Define to 1 if you have the header file. */ #undef HAVE_MEMORY_H /* MySQL is present */ #undef HAVE_MYSQL /* Check for optreset? */ #undef HAVE_OPTRESET /* PostgreSQL is present */ #undef HAVE_PGSQL /* Define to 1 if you have the `pselect' function. */ #undef HAVE_PSELECT /* Define to 1 if sockaddr has a sa_len member, and corresponding sin_len and sun_len */ #undef HAVE_SA_LEN /* Define to 1 if stdbool.h conforms to C99. */ #undef HAVE_STDBOOL_H /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H /* Define to 1 if you have the header file. */ #undef HAVE_STRINGS_H /* Define to 1 if you have the header file. */ #undef HAVE_STRING_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_DEVPOLL_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_FILIO_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_STAT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H /* Define to 1 if you have the header file. */ #undef HAVE_UTILS_ERRCODES_H /* Check valgrind headers */ #undef HAVE_VALGRIND_HEADERS /* Define to 1 if you have the header file. */ #undef HAVE_VALGRIND_VALGRIND_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 /* Running on BSD? */ #undef OS_BSD /* Running on FreeBSD? */ #undef OS_FREEBSD /* Running on Linux? */ #undef OS_LINUX /* Running on NetBSD? */ #undef OS_NETBSD /* Running on OpenBSD? */ #undef OS_OPENBSD /* Running on OSX? */ #undef OS_OSX /* Running on Solaris? */ #undef OS_SOLARIS /* Name of package */ #undef PACKAGE /* 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 /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS /* Was Kea statically linked? */ #undef USE_STATIC_LINK /* Version number of package */ #undef VERSION /* Compile with Botan crypto */ #undef WITH_BOTAN /* Compile with OpenSSL crypto */ #undef WITH_OPENSSL /* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a `char[]'. */ #undef YYTEXT_POINTER /* Define to `unsigned int' if does not define. */ #undef size_t kea-1.1.0/COPYING0000664000175000017500000007131512772017075010246 00000000000000Copyright (C) 2009-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/. Full text is also included below. ----------------------------------------------------------------------------- The ext/coroutine code is externally maintained and distributed under the Boost Software License, Version 1.0. (See its accompanying file ext/coroutine/LICENSE_1_0.txt.) ----------------------------------------------------------------------------- The Cassandra backend code is distributed under the Apache License, Version 2.0. The text is available at http://www.apache.org/licenses/LICENSE-2.0. Full text is also included below in this file. ----------------------------------------------------------------------------- For your convenience, full text of MPL 2.0 and Apache 2.0 licenses is available below: --- MPL 2.0 license --------------------------------------------------------- Mozilla Public License Version 2.0 ================================== 1. Definitions -------------- 1.1. "Contributor" means each individual or legal entity that creates, contributes to the creation of, or owns Covered Software. 1.2. "Contributor Version" means the combination of the Contributions of others (if any) used by a Contributor and that particular Contributor's Contribution. 1.3. "Contribution" means Covered Software of a particular Contributor. 1.4. "Covered Software" means Source Code Form to which the initial Contributor has attached the notice in Exhibit A, the Executable Form of such Source Code Form, and Modifications of such Source Code Form, in each case including portions thereof. 1.5. "Incompatible With Secondary Licenses" means (a) that the initial Contributor has attached the notice described in Exhibit B to the Covered Software; or (b) that the Covered Software was made available under the terms of version 1.1 or earlier of the License, but not also under the terms of a Secondary License. 1.6. "Executable Form" means any form of the work other than Source Code Form. 1.7. "Larger Work" means a work that combines Covered Software with other material, in a separate file or files, that is not Covered Software. 1.8. "License" means this document. 1.9. "Licensable" means having the right to grant, to the maximum extent possible, whether at the time of the initial grant or subsequently, any and all of the rights conveyed by this License. 1.10. "Modifications" means any of the following: (a) any file in Source Code Form that results from an addition to, deletion from, or modification of the contents of Covered Software; or (b) any new file in Source Code Form that contains any Covered Software. 1.11. "Patent Claims" of a Contributor means any patent claim(s), including without limitation, method, process, and apparatus claims, in any patent Licensable by such Contributor that would be infringed, but for the grant of the License, by the making, using, selling, offering for sale, having made, import, or transfer of either its Contributions or its Contributor Version. 1.12. "Secondary License" means either the GNU General Public License, Version 2.0, the GNU Lesser General Public License, Version 2.1, the GNU Affero General Public License, Version 3.0, or any later versions of those licenses. 1.13. "Source Code Form" means the form of the work preferred for making modifications. 1.14. "You" (or "Your") means an individual or a legal entity exercising rights under this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with You. For purposes of this definition, "control" means (a) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of more than fifty percent (50%) of the outstanding shares or beneficial ownership of such entity. 2. License Grants and Conditions -------------------------------- 2.1. Grants Each Contributor hereby grants You a world-wide, royalty-free, non-exclusive license: (a) under intellectual property rights (other than patent or trademark) Licensable by such Contributor to use, reproduce, make available, modify, display, perform, distribute, and otherwise exploit its Contributions, either on an unmodified basis, with Modifications, or as part of a Larger Work; and (b) under Patent Claims of such Contributor to make, use, sell, offer for sale, have made, import, and otherwise transfer either its Contributions or its Contributor Version. 2.2. Effective Date The licenses granted in Section 2.1 with respect to any Contribution become effective for each Contribution on the date the Contributor first distributes such Contribution. 2.3. Limitations on Grant Scope The licenses granted in this Section 2 are the only rights granted under this License. No additional rights or licenses will be implied from the distribution or licensing of Covered Software under this License. Notwithstanding Section 2.1(b) above, no patent license is granted by a Contributor: (a) for any code that a Contributor has removed from Covered Software; or (b) for infringements caused by: (i) Your and any other third party's modifications of Covered Software, or (ii) the combination of its Contributions with other software (except as part of its Contributor Version); or (c) under Patent Claims infringed by Covered Software in the absence of its Contributions. This License does not grant any rights in the trademarks, service marks, or logos of any Contributor (except as may be necessary to comply with the notice requirements in Section 3.4). 2.4. Subsequent Licenses No Contributor makes additional grants as a result of Your choice to distribute the Covered Software under a subsequent version of this License (see Section 10.2) or under the terms of a Secondary License (if permitted under the terms of Section 3.3). 2.5. Representation Each Contributor represents that the Contributor believes its Contributions are its original creation(s) or it has sufficient rights to grant the rights to its Contributions conveyed by this License. 2.6. Fair Use This License is not intended to limit any rights You have under applicable copyright doctrines of fair use, fair dealing, or other equivalents. 2.7. Conditions Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in Section 2.1. 3. Responsibilities ------------------- 3.1. Distribution of Source Form All distribution of Covered Software in Source Code Form, including any Modifications that You create or to which You contribute, must be under the terms of this License. You must inform recipients that the Source Code Form of the Covered Software is governed by the terms of this License, and how they can obtain a copy of this License. You may not attempt to alter or restrict the recipients' rights in the Source Code Form. 3.2. Distribution of Executable Form If You distribute Covered Software in Executable Form then: (a) such Covered Software must also be made available in Source Code Form, as described in Section 3.1, and You must inform recipients of the Executable Form how they can obtain a copy of such Source Code Form by reasonable means in a timely manner, at a charge no more than the cost of distribution to the recipient; and (b) You may distribute such Executable Form under the terms of this License, or sublicense it under different terms, provided that the license for the Executable Form does not attempt to limit or alter the recipients' rights in the Source Code Form under this License. 3.3. Distribution of a Larger Work You may create and distribute a Larger Work under terms of Your choice, provided that You also comply with the requirements of this License for the Covered Software. If the Larger Work is a combination of Covered Software with a work governed by one or more Secondary Licenses, and the Covered Software is not Incompatible With Secondary Licenses, this License permits You to additionally distribute such Covered Software under the terms of such Secondary License(s), so that the recipient of the Larger Work may, at their option, further distribute the Covered Software under the terms of either this License or such Secondary License(s). 3.4. Notices You may not remove or alter the substance of any license notices (including copyright notices, patent notices, disclaimers of warranty, or limitations of liability) contained within the Source Code Form of the Covered Software, except that You may alter any license notices to the extent required to remedy known factual inaccuracies. 3.5. Application of Additional Terms You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Software. However, You may do so only on Your own behalf, and not on behalf of any Contributor. You must make it absolutely clear that any such warranty, support, indemnity, or liability obligation is offered by You alone, and You hereby agree to indemnify every Contributor for any liability incurred by such Contributor as a result of warranty, support, indemnity or liability terms You offer. You may include additional disclaimers of warranty and limitations of liability specific to any jurisdiction. 4. Inability to Comply Due to Statute or Regulation --------------------------------------------------- If it is impossible for You to comply with any of the terms of this License with respect to some or all of the Covered Software due to statute, judicial order, or regulation then You must: (a) comply with the terms of this License to the maximum extent possible; and (b) describe the limitations and the code they affect. Such description must be placed in a text file included with all distributions of the Covered Software under this License. Except to the extent prohibited by statute or regulation, such description must be sufficiently detailed for a recipient of ordinary skill to be able to understand it. 5. Termination -------------- 5.1. The rights granted under this License will terminate automatically if You fail to comply with any of its terms. However, if You become compliant, then the rights granted under this License from a particular Contributor are reinstated (a) provisionally, unless and until such Contributor explicitly and finally terminates Your grants, and (b) on an ongoing basis, if such Contributor fails to notify You of the non-compliance by some reasonable means prior to 60 days after You have come back into compliance. Moreover, Your grants from a particular Contributor are reinstated on an ongoing basis if such Contributor notifies You of the non-compliance by some reasonable means, this is the first time You have received notice of non-compliance with this License from such Contributor, and You become compliant prior to 30 days after Your receipt of the notice. 5.2. If You initiate litigation against any entity by asserting a patent infringement claim (excluding declaratory judgment actions, counter-claims, and cross-claims) alleging that a Contributor Version directly or indirectly infringes any patent, then the rights granted to You by any and all Contributors for the Covered Software under Section 2.1 of this License shall terminate. 5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user license agreements (excluding distributors and resellers) which have been validly granted by You or Your distributors under this License prior to termination shall survive termination. ************************************************************************ * * * 6. Disclaimer of Warranty * * ------------------------- * * * * Covered Software is provided under this License on an "as is" * * basis, without warranty of any kind, either expressed, implied, or * * statutory, including, without limitation, warranties that the * * Covered Software is free of defects, merchantable, fit for a * * particular purpose or non-infringing. The entire risk as to the * * quality and performance of the Covered Software is with You. * * Should any Covered Software prove defective in any respect, You * * (not any Contributor) assume the cost of any necessary servicing, * * repair, or correction. This disclaimer of warranty constitutes an * * essential part of this License. No use of any Covered Software is * * authorized under this License except under this disclaimer. * * * ************************************************************************ ************************************************************************ * * * 7. Limitation of Liability * * -------------------------- * * * * Under no circumstances and under no legal theory, whether tort * * (including negligence), contract, or otherwise, shall any * * Contributor, or anyone who distributes Covered Software as * * permitted above, be liable to You for any direct, indirect, * * special, incidental, or consequential damages of any character * * including, without limitation, damages for lost profits, loss of * * goodwill, work stoppage, computer failure or malfunction, or any * * and all other commercial damages or losses, even if such party * * shall have been informed of the possibility of such damages. This * * limitation of liability shall not apply to liability for death or * * personal injury resulting from such party's negligence to the * * extent applicable law prohibits such limitation. Some * * jurisdictions do not allow the exclusion or limitation of * * incidental or consequential damages, so this exclusion and * * limitation may not apply to You. * * * ************************************************************************ 8. Litigation ------------- Any litigation relating to this License may be brought only in the courts of a jurisdiction where the defendant maintains its principal place of business and such litigation shall be governed by laws of that jurisdiction, without reference to its conflict-of-law provisions. Nothing in this Section shall prevent a party's ability to bring cross-claims or counter-claims. 9. Miscellaneous ---------------- This License represents the complete agreement concerning the subject matter hereof. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. Any law or regulation which provides that the language of a contract shall be construed against the drafter shall not be used to construe this License against a Contributor. 10. Versions of the License --------------------------- 10.1. New Versions Mozilla Foundation is the license steward. Except as provided in Section 10.3, no one other than the license steward has the right to modify or publish new versions of this License. Each version will be given a distinguishing version number. 10.2. Effect of New Versions You may distribute the Covered Software under the terms of the version of the License under which You originally received the Covered Software, or under the terms of any subsequent version published by the license steward. 10.3. Modified Versions If you create software not governed by this License, and you want to create a new license for such software, you may create and use a modified version of this License if you rename the license and remove any references to the name of the license steward (except to note that such modified license differs from this License). 10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses If You choose to distribute Source Code Form that is Incompatible With Secondary Licenses under the terms of this version of the License, the notice described in Exhibit B of this License must be attached. Exhibit A - Source Code Form License Notice ------------------------------------------- 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/. If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice. You may add additional accurate notices of copyright ownership. Exhibit B - "Incompatible With Secondary Licenses" Notice --------------------------------------------------------- This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0. ---end of MPL 2.0 license --------------------------------------------------- --- Apache 2.0 license ------------------------------------------------------ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. --- end of Apache 2.0 license ----------------------------------------------- kea-1.1.0/doc/0000775000175000017500000000000012772742656010043 500000000000000kea-1.1.0/doc/Makefile.in0000664000175000017500000005674112772742613012036 00000000000000# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = doc DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(srcdir)/version.ent.in $(nobase_dist_doc_DATA) ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4macros/ax_boost_for_kea.m4 \ $(top_srcdir)/m4macros/ax_isc_rpath.m4 \ $(top_srcdir)/m4macros/libtool.m4 \ $(top_srcdir)/m4macros/ltoptions.m4 \ $(top_srcdir)/m4macros/ltsugar.m4 \ $(top_srcdir)/m4macros/ltversion.m4 \ $(top_srcdir)/m4macros/lt~obsolete.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = version.ent CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ install-exec-recursive install-html-recursive \ install-info-recursive install-pdf-recursive \ install-ps-recursive install-recursive installcheck-recursive \ installdirs-recursive pdf-recursive ps-recursive \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(docdir)" DATA = $(nobase_dist_doc_DATA) RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ distdir am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DIST_SUBDIRS = $(SUBDIRS) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ASCIIDOC = @ASCIIDOC@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BOOST_INCLUDES = @BOOST_INCLUDES@ BOOST_LIBS = @BOOST_LIBS@ BOTAN_TOOL = @BOTAN_TOOL@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CQL_CPPFLAGS = @CQL_CPPFLAGS@ CQL_LIBS = @CQL_LIBS@ CRYPTO_CFLAGS = @CRYPTO_CFLAGS@ CRYPTO_INCLUDES = @CRYPTO_INCLUDES@ CRYPTO_LDFLAGS = @CRYPTO_LDFLAGS@ CRYPTO_LIBS = @CRYPTO_LIBS@ CRYPTO_PACKAGE = @CRYPTO_PACKAGE@ CRYPTO_RPATH = @CRYPTO_RPATH@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DBLATEX = @DBLATEX@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DISTCHECK_BOOST_CONFIGURE_FLAG = @DISTCHECK_BOOST_CONFIGURE_FLAG@ DISTCHECK_CRYPTO_CONFIGURE_FLAG = @DISTCHECK_CRYPTO_CONFIGURE_FLAG@ DISTCHECK_GTEST_CONFIGURE_FLAG = @DISTCHECK_GTEST_CONFIGURE_FLAG@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ ELINKS = @ELINKS@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GENHTML = @GENHTML@ GREP = @GREP@ GTEST_CONFIG = @GTEST_CONFIG@ GTEST_INCLUDES = @GTEST_INCLUDES@ GTEST_LDADD = @GTEST_LDADD@ GTEST_LDFLAGS = @GTEST_LDFLAGS@ GTEST_SOURCE = @GTEST_SOURCE@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ KEA_CXXFLAGS = @KEA_CXXFLAGS@ LCOV = @LCOV@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LEXLIB = @LEXLIB@ LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LOG4CPLUS_INCLUDES = @LOG4CPLUS_INCLUDES@ LOG4CPLUS_LIBS = @LOG4CPLUS_LIBS@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ MYSQL_LIBS = @MYSQL_LIBS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PERL = @PERL@ PGSQL_CPPFLAGS = @PGSQL_CPPFLAGS@ PGSQL_LIBS = @PGSQL_LIBS@ PKG_CONFIG = @PKG_CONFIG@ PLANTUML = @PLANTUML@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SEP = @SEP@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ USE_LCOV = @USE_LCOV@ VALGRIND = @VALGRIND@ VERSION = @VERSION@ WARNING_GCC_44_STRICT_ALIASING_CFLAG = @WARNING_GCC_44_STRICT_ALIASING_CFLAG@ XSLTPROC = @XSLTPROC@ YACC = @YACC@ YFLAGS = @YFLAGS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ SUBDIRS = guide design EXTRA_DIST = version.ent.in Doxyfile Doxyfile-xml \ devel/config-backend.dox devel/contribute.dox \ devel/mainpage.dox devel/unit-tests.dox nobase_dist_doc_DATA = examples/ddns/sample1.json \ examples/ddns/template.json examples/kea4/backends.json \ examples/kea4/classify.json examples/kea4/hooks.json \ examples/kea4/leases-expiration.json \ examples/kea4/multiple-options.json \ examples/kea4/mysql-reservations.json \ examples/kea4/pgsql-reservations.json \ examples/kea4/reservations.json \ examples/kea4/several-subnets.json \ examples/kea4/single-subnet.json examples/kea6/advanced.json \ examples/kea6/backends.json examples/kea6/classify.json \ examples/kea6/hooks.json examples/kea6/leases-expiration.json \ examples/kea6/multiple-options.json \ examples/kea6/mysql-reservations.json \ examples/kea6/pgsql-reservations.json \ examples/kea6/reservations.json \ examples/kea6/several-subnets.json examples/kea6/simple.json \ examples/kea6/stateless.json examples/kea6/duid.json all: all-recursive .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign doc/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign doc/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): version.ent: $(top_builddir)/config.status $(srcdir)/version.ent.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-nobase_dist_docDATA: $(nobase_dist_doc_DATA) @$(NORMAL_INSTALL) @list='$(nobase_dist_doc_DATA)'; test -n "$(docdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(docdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(docdir)" || exit 1; \ fi; \ $(am__nobase_list) | while read dir files; do \ xfiles=; for file in $$files; do \ if test -f "$$file"; then xfiles="$$xfiles $$file"; \ else xfiles="$$xfiles $(srcdir)/$$file"; fi; done; \ test -z "$$xfiles" || { \ test "x$$dir" = x. || { \ echo " $(MKDIR_P) '$(DESTDIR)$(docdir)/$$dir'"; \ $(MKDIR_P) "$(DESTDIR)$(docdir)/$$dir"; }; \ echo " $(INSTALL_DATA) $$xfiles '$(DESTDIR)$(docdir)/$$dir'"; \ $(INSTALL_DATA) $$xfiles "$(DESTDIR)$(docdir)/$$dir" || exit $$?; }; \ done uninstall-nobase_dist_docDATA: @$(NORMAL_UNINSTALL) @list='$(nobase_dist_doc_DATA)'; test -n "$(docdir)" || list=; \ $(am__nobase_strip_setup); files=`$(am__nobase_strip)`; \ dir='$(DESTDIR)$(docdir)'; $(am__uninstall_files_from_dir) # This directory's subdirectories are mostly independent; you can cd # into them and run 'make' without going through this Makefile. # To change the values of 'make' variables: instead of editing Makefiles, # (1) if the variable is set in 'config.status', edit 'config.status' # (which will cause the Makefiles to be regenerated when you run 'make'); # (2) otherwise, pass the desired values on the 'make' command line. $(am__recursive_targets): @fail=; \ if $(am__make_keepgoing); then \ failcom='fail=yes'; \ else \ failcom='exit 1'; \ fi; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-recursive CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-recursive cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done check-am: all-am check: check-recursive all-am: Makefile $(DATA) installdirs: installdirs-recursive installdirs-am: for dir in "$(DESTDIR)$(docdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-recursive -rm -f Makefile distclean-am: clean-am distclean-generic distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-nobase_dist_docDATA install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: uninstall-nobase_dist_docDATA .MAKE: $(am__recursive_targets) install-am install-strip .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ check-am clean clean-generic clean-libtool cscopelist-am ctags \ ctags-am distclean distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-nobase_dist_docDATA install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs installdirs-am maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-nobase_dist_docDATA devel: mkdir -p html (cat Doxyfile; echo PROJECT_NUMBER=$(PACKAGE_VERSION)) | doxygen - > html/doxygen.log 2> html/doxygen-error.log echo `grep -i ": warning:" html/doxygen-error.log | wc -l` warnings/errors detected. guide: $(MAKE) -C guide kea-guide.html clean: rm -rf html # That's a bit of a hack, but we are making sure that devel target # is always valid. The alternative is to make devel depend on all # *.cc *.h files in the whole tree. .PHONY: devel guide # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: kea-1.1.0/doc/Makefile.am0000664000175000017500000000404112772742522012006 00000000000000SUBDIRS = guide design EXTRA_DIST = version.ent.in Doxyfile Doxyfile-xml EXTRA_DIST += devel/config-backend.dox EXTRA_DIST += devel/contribute.dox EXTRA_DIST += devel/mainpage.dox EXTRA_DIST += devel/unit-tests.dox nobase_dist_doc_DATA = examples/ddns/sample1.json nobase_dist_doc_DATA += examples/ddns/template.json nobase_dist_doc_DATA += examples/kea4/backends.json nobase_dist_doc_DATA += examples/kea4/classify.json nobase_dist_doc_DATA += examples/kea4/hooks.json nobase_dist_doc_DATA += examples/kea4/leases-expiration.json nobase_dist_doc_DATA += examples/kea4/multiple-options.json nobase_dist_doc_DATA += examples/kea4/mysql-reservations.json nobase_dist_doc_DATA += examples/kea4/pgsql-reservations.json nobase_dist_doc_DATA += examples/kea4/reservations.json nobase_dist_doc_DATA += examples/kea4/several-subnets.json nobase_dist_doc_DATA += examples/kea4/single-subnet.json nobase_dist_doc_DATA += examples/kea6/advanced.json nobase_dist_doc_DATA += examples/kea6/backends.json nobase_dist_doc_DATA += examples/kea6/classify.json nobase_dist_doc_DATA += examples/kea6/hooks.json nobase_dist_doc_DATA += examples/kea6/leases-expiration.json nobase_dist_doc_DATA += examples/kea6/multiple-options.json nobase_dist_doc_DATA += examples/kea6/mysql-reservations.json nobase_dist_doc_DATA += examples/kea6/pgsql-reservations.json nobase_dist_doc_DATA += examples/kea6/reservations.json nobase_dist_doc_DATA += examples/kea6/several-subnets.json nobase_dist_doc_DATA += examples/kea6/simple.json nobase_dist_doc_DATA += examples/kea6/stateless.json nobase_dist_doc_DATA += examples/kea6/duid.json devel: mkdir -p html (cat Doxyfile; echo PROJECT_NUMBER=$(PACKAGE_VERSION)) | doxygen - > html/doxygen.log 2> html/doxygen-error.log echo `grep -i ": warning:" html/doxygen-error.log | wc -l` warnings/errors detected. guide: $(MAKE) -C guide kea-guide.html clean: rm -rf html # That's a bit of a hack, but we are making sure that devel target # is always valid. The alternative is to make devel depend on all # *.cc *.h files in the whole tree. .PHONY: devel guide kea-1.1.0/doc/design/0000775000175000017500000000000012772742656011314 500000000000000kea-1.1.0/doc/design/Makefile.in0000664000175000017500000004665212772742613013307 00000000000000# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = doc/design DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4macros/ax_boost_for_kea.m4 \ $(top_srcdir)/m4macros/ax_isc_rpath.m4 \ $(top_srcdir)/m4macros/libtool.m4 \ $(top_srcdir)/m4macros/ltoptions.m4 \ $(top_srcdir)/m4macros/ltsugar.m4 \ $(top_srcdir)/m4macros/ltversion.m4 \ $(top_srcdir)/m4macros/lt~obsolete.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ install-exec-recursive install-html-recursive \ install-info-recursive install-pdf-recursive \ install-ps-recursive install-recursive installcheck-recursive \ installdirs-recursive pdf-recursive ps-recursive \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ distdir am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DIST_SUBDIRS = $(SUBDIRS) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ASCIIDOC = @ASCIIDOC@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BOOST_INCLUDES = @BOOST_INCLUDES@ BOOST_LIBS = @BOOST_LIBS@ BOTAN_TOOL = @BOTAN_TOOL@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CQL_CPPFLAGS = @CQL_CPPFLAGS@ CQL_LIBS = @CQL_LIBS@ CRYPTO_CFLAGS = @CRYPTO_CFLAGS@ CRYPTO_INCLUDES = @CRYPTO_INCLUDES@ CRYPTO_LDFLAGS = @CRYPTO_LDFLAGS@ CRYPTO_LIBS = @CRYPTO_LIBS@ CRYPTO_PACKAGE = @CRYPTO_PACKAGE@ CRYPTO_RPATH = @CRYPTO_RPATH@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DBLATEX = @DBLATEX@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DISTCHECK_BOOST_CONFIGURE_FLAG = @DISTCHECK_BOOST_CONFIGURE_FLAG@ DISTCHECK_CRYPTO_CONFIGURE_FLAG = @DISTCHECK_CRYPTO_CONFIGURE_FLAG@ DISTCHECK_GTEST_CONFIGURE_FLAG = @DISTCHECK_GTEST_CONFIGURE_FLAG@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ ELINKS = @ELINKS@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GENHTML = @GENHTML@ GREP = @GREP@ GTEST_CONFIG = @GTEST_CONFIG@ GTEST_INCLUDES = @GTEST_INCLUDES@ GTEST_LDADD = @GTEST_LDADD@ GTEST_LDFLAGS = @GTEST_LDFLAGS@ GTEST_SOURCE = @GTEST_SOURCE@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ KEA_CXXFLAGS = @KEA_CXXFLAGS@ LCOV = @LCOV@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LEXLIB = @LEXLIB@ LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LOG4CPLUS_INCLUDES = @LOG4CPLUS_INCLUDES@ LOG4CPLUS_LIBS = @LOG4CPLUS_LIBS@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ MYSQL_LIBS = @MYSQL_LIBS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PERL = @PERL@ PGSQL_CPPFLAGS = @PGSQL_CPPFLAGS@ PGSQL_LIBS = @PGSQL_LIBS@ PKG_CONFIG = @PKG_CONFIG@ PLANTUML = @PLANTUML@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SEP = @SEP@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ USE_LCOV = @USE_LCOV@ VALGRIND = @VALGRIND@ VERSION = @VERSION@ WARNING_GCC_44_STRICT_ALIASING_CFLAG = @WARNING_GCC_44_STRICT_ALIASING_CFLAG@ XSLTPROC = @XSLTPROC@ YACC = @YACC@ YFLAGS = @YFLAGS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ SUBDIRS = datasrc all: all-recursive .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign doc/design/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign doc/design/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs # This directory's subdirectories are mostly independent; you can cd # into them and run 'make' without going through this Makefile. # To change the values of 'make' variables: instead of editing Makefiles, # (1) if the variable is set in 'config.status', edit 'config.status' # (which will cause the Makefiles to be regenerated when you run 'make'); # (2) otherwise, pass the desired values on the 'make' command line. $(am__recursive_targets): @fail=; \ if $(am__make_keepgoing); then \ failcom='fail=yes'; \ else \ failcom='exit 1'; \ fi; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-recursive CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-recursive cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done check-am: all-am check: check-recursive all-am: Makefile installdirs: installdirs-recursive installdirs-am: install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-recursive clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-recursive -rm -f Makefile distclean-am: clean-am distclean-generic distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: .MAKE: $(am__recursive_targets) install-am install-strip .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ check-am clean clean-generic clean-libtool cscopelist-am ctags \ ctags-am distclean distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ installdirs-am maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ ps ps-am tags tags-am uninstall uninstall-am # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: kea-1.1.0/doc/design/datasrc/0000775000175000017500000000000012772742656012735 500000000000000kea-1.1.0/doc/design/datasrc/Makefile.in0000664000175000017500000003367712772742613014733 00000000000000# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = doc/design/datasrc DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4macros/ax_boost_for_kea.m4 \ $(top_srcdir)/m4macros/ax_isc_rpath.m4 \ $(top_srcdir)/m4macros/libtool.m4 \ $(top_srcdir)/m4macros/ltoptions.m4 \ $(top_srcdir)/m4macros/ltsugar.m4 \ $(top_srcdir)/m4macros/ltversion.m4 \ $(top_srcdir)/m4macros/lt~obsolete.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ASCIIDOC = @ASCIIDOC@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BOOST_INCLUDES = @BOOST_INCLUDES@ BOOST_LIBS = @BOOST_LIBS@ BOTAN_TOOL = @BOTAN_TOOL@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CQL_CPPFLAGS = @CQL_CPPFLAGS@ CQL_LIBS = @CQL_LIBS@ CRYPTO_CFLAGS = @CRYPTO_CFLAGS@ CRYPTO_INCLUDES = @CRYPTO_INCLUDES@ CRYPTO_LDFLAGS = @CRYPTO_LDFLAGS@ CRYPTO_LIBS = @CRYPTO_LIBS@ CRYPTO_PACKAGE = @CRYPTO_PACKAGE@ CRYPTO_RPATH = @CRYPTO_RPATH@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DBLATEX = @DBLATEX@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DISTCHECK_BOOST_CONFIGURE_FLAG = @DISTCHECK_BOOST_CONFIGURE_FLAG@ DISTCHECK_CRYPTO_CONFIGURE_FLAG = @DISTCHECK_CRYPTO_CONFIGURE_FLAG@ DISTCHECK_GTEST_CONFIGURE_FLAG = @DISTCHECK_GTEST_CONFIGURE_FLAG@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ ELINKS = @ELINKS@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GENHTML = @GENHTML@ GREP = @GREP@ GTEST_CONFIG = @GTEST_CONFIG@ GTEST_INCLUDES = @GTEST_INCLUDES@ GTEST_LDADD = @GTEST_LDADD@ GTEST_LDFLAGS = @GTEST_LDFLAGS@ GTEST_SOURCE = @GTEST_SOURCE@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ KEA_CXXFLAGS = @KEA_CXXFLAGS@ LCOV = @LCOV@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LEXLIB = @LEXLIB@ LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LOG4CPLUS_INCLUDES = @LOG4CPLUS_INCLUDES@ LOG4CPLUS_LIBS = @LOG4CPLUS_LIBS@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ MYSQL_LIBS = @MYSQL_LIBS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PERL = @PERL@ PGSQL_CPPFLAGS = @PGSQL_CPPFLAGS@ PGSQL_LIBS = @PGSQL_LIBS@ PKG_CONFIG = @PKG_CONFIG@ PLANTUML = @PLANTUML@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SEP = @SEP@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ USE_LCOV = @USE_LCOV@ VALGRIND = @VALGRIND@ VERSION = @VERSION@ WARNING_GCC_44_STRICT_ALIASING_CFLAG = @WARNING_GCC_44_STRICT_ALIASING_CFLAG@ XSLTPROC = @XSLTPROC@ YACC = @YACC@ YFLAGS = @YFLAGS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ UML_FILES = \ overview.txt \ auth-local.txt \ auth-mapped.txt \ memmgr-mapped-init.txt \ memmgr-mapped-reload.txt TEXT_FILES = \ data-source-classes.txt CLEANFILES = \ $(patsubst %.txt, %.png, $(UML_FILES)) \ $(patsubst %.txt, %.html, $(TEXT_FILES)) \ $(patsubst %.txt, %.xml, $(TEXT_FILES)) all: all-am .SUFFIXES: .SUFFIXES: .html .png .txt $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign doc/design/datasrc/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign doc/design/datasrc/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags-am uninstall uninstall-am devel: $(patsubst %.txt, %.png, $(UML_FILES)) $(patsubst %.txt, %.html, $(TEXT_FILES)) .txt.html: @HAVE_ASCIIDOC_TRUE@ $(AM_V_GEN) $(ASCIIDOC) -n $< @HAVE_ASCIIDOC_FALSE@ @echo "*** asciidoc is required to regenerate $(@) ***"; exit 1; .txt.png: @HAVE_PLANTUML_TRUE@ $(AM_V_GEN) $(PLANTUML) $< @HAVE_PLANTUML_FALSE@ @echo "*** plantuml is required to regenerate $(@) ***"; exit 1; # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: kea-1.1.0/doc/design/datasrc/Makefile.am0000664000175000017500000000122512772017075014677 00000000000000UML_FILES = \ overview.txt \ auth-local.txt \ auth-mapped.txt \ memmgr-mapped-init.txt \ memmgr-mapped-reload.txt TEXT_FILES = \ data-source-classes.txt devel: $(patsubst %.txt, %.png, $(UML_FILES)) $(patsubst %.txt, %.html, $(TEXT_FILES)) .txt.html: if HAVE_ASCIIDOC $(AM_V_GEN) $(ASCIIDOC) -n $< else @echo "*** asciidoc is required to regenerate $(@) ***"; exit 1; endif .txt.png: if HAVE_PLANTUML $(AM_V_GEN) $(PLANTUML) $< else @echo "*** plantuml is required to regenerate $(@) ***"; exit 1; endif CLEANFILES = \ $(patsubst %.txt, %.png, $(UML_FILES)) \ $(patsubst %.txt, %.html, $(TEXT_FILES)) \ $(patsubst %.txt, %.xml, $(TEXT_FILES)) kea-1.1.0/doc/design/Makefile.am0000664000175000017500000000002212772017075013250 00000000000000SUBDIRS = datasrc kea-1.1.0/doc/version.ent.in0000664000175000017500000000005212772017075012550 00000000000000 kea-1.1.0/doc/Doxyfile0000664000175000017500000030467212772017075011473 00000000000000# Doxyfile 1.8.6 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. # # All text after a double hash (##) is considered a comment and is placed in # front of the TAG it is preceding. # # All text after a hash (#) is considered a comment and will be ignored. # The format is: # TAG = value [value, ...] # For lists items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (" "). #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # This tag specifies the encoding used for all characters in the config file # that follow. The default is UTF-8 which is also the encoding used for all # text before the first occurrence of this tag. Doxygen uses libiconv (or the # iconv built into libc) for the transcoding. See # http://www.gnu.org/software/libiconv for the list of possible encodings. # The default value is: UTF-8. DOXYFILE_ENCODING = UTF-8 # The PROJECT_NAME tag is a single word (or sequence of words) that should # identify the project. Note that if you do not use Doxywizard you need # to put quotes around the project name if it contains spaces. # The default value is: My Project. PROJECT_NAME = Kea # The PROJECT_NUMBER tag can be used to enter a project or revision number. # This could be handy for archiving the generated documentation or # if some version control system is used. PROJECT_NUMBER = # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer # a quick idea about the purpose of the project. Keep the description short. PROJECT_BRIEF = # With the PROJECT_LOGO tag one can specify an logo or icon that is # included in the documentation. The maximum height of the logo should not # exceed 55 pixels and the maximum width should not exceed 200 pixels. # Doxygen will copy the logo to the output directory. PROJECT_LOGO = guide/kea-logo-100x70.png # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. # If a relative path is entered, it will be relative to the location # where doxygen was started. If left blank the current directory will be used. OUTPUT_DIRECTORY = html # If the CREATE_SUBDIRS tag is set to YES then doxygen will create # 4096 sub-directories (in 2 levels) under the output directory of each output # format and will distribute the generated files over these directories. # Enabling this option can be useful when feeding doxygen a huge amount of # source files, where putting all generated files in the same directory would # otherwise cause performance problems for the file system. # The default value is: NO. CREATE_SUBDIRS = YES # If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII # characters to appear in the names of generated files. If set to NO, non-ASCII # characters will be escaped, for example _xE3_x81_x84 will be used for Unicode # U+3044. # The default value is: NO. # XXX Only in 1.8.10 #ALLOW_UNICODE_NAMES = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # The default language is English, other supported languages are: # Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, # Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, # Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English # messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, # Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, # Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. # The default value is: English. OUTPUT_LANGUAGE = English # If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will # include brief member descriptions after the members that are listed in # the file and class documentation (similar to JavaDoc). # Set to NO to disable this. # The default value is: YES. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend # the brief description of a member or function before the detailed description. # Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. # The default value is: YES. REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator # that is used to form the text in various listings. Each string # in this list, if found as the leading text of the brief description, will be # stripped from the text and the result after processing the whole list, is # used as the annotated text. Otherwise, the brief description is used as-is. # If left blank, the following values are used ("$name" is automatically # replaced with the name of the entity): "The $name class" "The $name widget" # "The $name file" "is" "provides" "specifies" "contains" # "represents" "a" "an" "the". ABBREVIATE_BRIEF = # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # Doxygen will generate a detailed section even if there is only a brief # description. # The default value is: NO. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. # The default value is: NO. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full # path before files name in the file list and in the header files. If set # to NO the shortest path that makes the file name unique will be used. # The default value is: YES. FULL_PATH_NAMES = NO # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag # can be used to strip a user-defined part of the path. Stripping is # only done if one of the specified strings matches the left-hand part of # the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the # path to strip. # # Note that you can specify absolute paths here, but also relative paths, which # will be relative from the directory where doxygen is started. # This tag requires that the tag FULL_PATH_NAMES is set to YES. STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of # the path mentioned in the documentation of a class, which tells # the reader which header file to include in order to use a class. # If left blank only the name of the header file containing the class # definition is used. Otherwise one should specify the include paths that # are normally passed to the compiler using the -I flag. STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter # (but less readable) file names. This can be useful if your file system # doesn't support long names like on DOS, Mac, or CD-ROM. # The default value is: NO. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen # will interpret the first line (until the first dot) of a JavaDoc-style # comment as the brief description. If set to NO, the JavaDoc # comments will behave just like regular Qt-style comments # (thus requiring an explicit @brief command for a brief description.) # The default value is: NO. JAVADOC_AUTOBRIEF = YES # If the QT_AUTOBRIEF tag is set to YES then Doxygen will # interpret the first line (until the first dot) of a Qt-style # comment as the brief description. If set to NO, the comments # will behave just like regular Qt-style comments (thus requiring # an explicit \brief command for a brief description.) # The default value is: NO. QT_AUTOBRIEF = NO # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen # treat a multi-line C++ special comment block (i.e. a block of //! or /// # comments) as a brief description. This used to be the default behaviour. # The new default is to treat a multi-line C++ comment block as a detailed # description. Set this tag to YES if you prefer the old behaviour instead. # # Note that setting this tag to YES also means that rational rose comments are # not recognized any more. # The default value is: NO. MULTILINE_CPP_IS_BRIEF = NO # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented # member inherits the documentation from any documented member that it # re-implements. # The default value is: YES. INHERIT_DOCS = YES # If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce # a new page for each member. If set to NO, the documentation of a member will # be part of the file/class/namespace that contains it. # The default value is: NO. SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. # Doxygen uses this value to replace tabs by spaces in code fragments. # Minimum value: 1, maximum value: 16, default value: 4. TAB_SIZE = 4 # This tag can be used to specify a number of aliases that acts # as commands in the documentation. An alias has the form "name=value". # For example adding "sideeffect=\par Side Effects:\n" will allow you to # put the command \sideeffect (or @sideeffect) in the documentation, which # will result in a user-defined paragraph with heading "Side Effects:". # You can put \n's in the value part of an alias to insert newlines. ALIASES = # This tag can be used to specify a number of word-keyword mappings (TCL only). # A mapping has the form "name=value". For example adding # "class=itcl::class" will allow you to use the command class in the # itcl::class meaning. TCL_SUBST = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C # sources only. Doxygen will then generate output that is more tailored for C. # For instance, some of the names that are used will be different. The list # of all members will be omitted, etc. # The default value is: NO. OPTIMIZE_OUTPUT_FOR_C = NO # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java # sources only. Doxygen will then generate output that is more tailored for # Java. For instance, namespaces will be presented as packages, qualified # scopes will look different, etc. # The default value is: NO. OPTIMIZE_OUTPUT_JAVA = NO # Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran # sources only. Doxygen will then generate output that is more tailored for # Fortran. # The default value is: NO. OPTIMIZE_FOR_FORTRAN = NO # Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL # sources. Doxygen will then generate output that is tailored for # VHDL. # The default value is: NO. OPTIMIZE_OUTPUT_VHDL = NO # Doxygen selects the parser to use depending on the extension of the files it # parses. With this tag you can assign which parser to use for a given # extension. Doxygen has a built-in mapping, but you can override or extend it # using this tag. The format is ext=language, where ext is a file extension, # and language is one of the parsers supported by doxygen: IDL, Java, # Javascript, CSharp, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, # C++. For instance to make doxygen treat .inc files as Fortran files (default # is PHP), and .f files as C (default is Fortran), use: inc=Fortran f=C. # # Note For files without extension you can use no_extension as a placeholder. # # Note that for custom extensions you also need to set FILE_PATTERNS otherwise # the files are not read by doxygen. EXTENSION_MAPPING = # If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all # comments according to the Markdown format, which allows for more readable # documentation. See http://daringfireball.net/projects/markdown/ for details. # The output of markdown processing is further processed by doxygen, so you # can mix doxygen, HTML, and XML commands with Markdown formatting. # Disable only in case of backward compatibilities issues. # The default value is: YES. MARKDOWN_SUPPORT = YES # When enabled doxygen tries to link words that correspond to documented classes, # or namespaces to their corresponding documentation. Such a link can be # prevented in individual cases by by putting a % sign in front of the word or # globally by setting AUTOLINK_SUPPORT to NO. # The default value is: YES. AUTOLINK_SUPPORT = YES # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want # to include (a tag file for) the STL sources as input, then you should # set this tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); v.s. # func(std::string) {}). This also makes the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. # The default value is: NO. BUILTIN_STL_SUPPORT = YES # If you use Microsoft's C++/CLI language, you should set this option to YES to # enable parsing support. # The default value is: NO. CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. # Doxygen will parse them like normal C++ but will assume all classes use public # instead of private inheritance when no explicit protection keyword is present. # The default value is: NO. SIP_SUPPORT = NO # For Microsoft's IDL there are propget and propput attributes to indicate getter and setter methods for a property. Setting this option to YES (the default) will make doxygen replace the get and set methods by a property in the documentation. This will only work if the methods are indeed getting or setting a simple type. If this is not the case, or you want to show the methods anyway, you should set this option to NO. # The default value is: YES. IDL_PROPERTY_SUPPORT = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. # The default value is: NO. DISTRIBUTE_GROUP_DOC = NO # If one adds a struct or class to a group and this option is enabled, # then also any nested class or struct is added to the same group. By # default this option is disabled and one has to add nested compounds # explicitly via \ingroup. # The default value is: NO. # XXX Only in 1.8.10 #GROUP_NESTED_COMPOUNDS = NO # Set the SUBGROUPING tag to YES (the default) to allow class member groups of # the same type (for instance a group of public functions) to be put as a # subgroup of that type (e.g. under the Public Functions section). Set it to # NO to prevent subgrouping. Alternatively, this can be done per class using # the \nosubgrouping command. # The default value is: YES. SUBGROUPING = YES # When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and # unions are shown inside the group in which they are included (e.g. using # @ingroup) instead of on a separate page (for HTML and Man pages) or # section (for LaTeX and RTF). # The default value is: NO. INLINE_GROUPED_CLASSES = NO # When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and # unions with only public data fields will be shown inline in the documentation # of the scope in which they are defined (i.e. file, namespace, or group # documentation), provided this scope is documented. If set to NO (the default), # structs, classes, and unions are shown on a separate page (for HTML and Man # pages) or section (for LaTeX and RTF). # The default value is: NO. INLINE_SIMPLE_STRUCTS = NO # When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum # is documented as struct, union, or enum with the name of the typedef. So # typedef struct TypeS {} TypeT, will appear in the documentation as a struct # with name TypeT. When disabled the typedef will appear as a member of a file, # namespace, or class. And the struct will be named TypeS. This can typically # be useful for C code in case the coding convention dictates that all compound # types are typedef'ed and only the typedef is referenced, never the tag name. # The default value is: NO. TYPEDEF_HIDES_STRUCT = NO # Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be # set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given # their name and scope. Since this can be an expensive process and often the # same symbol appear multiple times in the code, doxygen keeps a cache of # pre-resolved symbols. If the cache is too small doxygen will become slower. # If the cache is too large, memory is wasted. The cache size is given by this # formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0, # corresponding to a cache size of 2^16 = 65536 symbols. # Minimum value: 0, maximum value: 9, default value: 0. LOOKUP_CACHE_SIZE = 0 #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. # Private class members and static file members will be hidden unless # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES # Note: This will also disable the warnings about undocumented members that are # normally produced when WARNINGS is set to YES. # The default value is: NO. EXTRACT_ALL = YES # If the EXTRACT_PRIVATE tag is set to YES all private members of a class # will be included in the documentation. # The default value is: NO. EXTRACT_PRIVATE = NO # If the EXTRACT_PACKAGE tag is set to YES all members with package or internal # scope will be included in the documentation. # The default value is: NO. EXTRACT_PACKAGE = NO # If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. # The default value is: NO. EXTRACT_STATIC = NO # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) # defined locally in source files will be included in the documentation. # If set to NO only classes defined in header files are included. # The default value is: YES. EXTRACT_LOCAL_CLASSES = YES # This flag is only useful for Objective-C code. When set to YES local # methods, which are defined in the implementation section but not in # the interface are included in the documentation. # If set to NO (the default) only methods in the interface are included. # The default value is: NO. EXTRACT_LOCAL_METHODS = NO # If this flag is set to YES, the members of anonymous namespaces will be # extracted and appear in the documentation as a namespace called # 'anonymous_namespace{file}', where file will be replaced with the base # name of the file that contains the anonymous namespace. By default # anonymous namespaces are hidden. # The default value is: NO. EXTRACT_ANON_NSPACES = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all # undocumented members of documented classes, files or namespaces. # If set to NO (the default) these members will be included in the # various overviews, but no documentation section is generated. # This option has no effect if EXTRACT_ALL is enabled. # The default value is: NO. HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. # If set to NO (the default) these classes will be included in the various # overviews. This option has no effect if EXTRACT_ALL is enabled. # The default value is: NO. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all # friend (class|struct|union) declarations. # If set to NO (the default) these declarations will be included in the # documentation. # The default value is: NO. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any # documentation blocks found inside the body of a function. # If set to NO (the default) these blocks will be appended to the # function's detailed documentation block. # The default value is: NO. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation # that is typed after a \internal command is included. If the tag is set # to NO (the default) then the documentation will be excluded. # Set it to YES to include the internal documentation. # The default value is: NO. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate # file names in lower-case letters. If set to YES upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. # The default value is: system dependent. CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen # will show members with their full class and namespace scopes in the # documentation. If set to YES the scope will be hidden. # The default value is: NO. HIDE_SCOPE_NAMES = NO # If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will # append additional text to a page's title, such as Class Reference. If set to # YES the compound reference will be hidden. # The default value is: NO. # XXX Only in 1.8.10 #HIDE_COMPOUND_REFERENCE= NO # If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen # will put a list of the files that are included by a file in the documentation # of that file. # The default value is: YES. SHOW_INCLUDE_FILES = YES # If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen # will list include files with double quotes in the documentation # rather than with sharp brackets. # The default value is: NO. FORCE_LOCAL_INCLUDES = NO # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # is inserted in the documentation for inline members. # The default value is: YES. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen # will sort the (detailed) documentation of file and class members # alphabetically by member name. If set to NO the members will appear in # declaration order. # The default value is: YES. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the # brief documentation of file, namespace and class members alphabetically # by member name. If set to NO (the default) the members will appear in # declaration order. # The default value is: NO. SORT_BRIEF_DOCS = YES # If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen # will sort the (brief and detailed) documentation of class members so that # constructors and destructors are listed first. If set to NO (the default) # the constructors will appear in the respective orders defined by # SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. # This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO # and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. # The default value is: NO. SORT_MEMBERS_CTORS_1ST = YES # If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the # hierarchy of group names into alphabetical order. If set to NO (the default) # the group names will appear in their defined order. # The default value is: NO. SORT_GROUP_NAMES = YES # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be # sorted by fully-qualified names, including namespaces. If set to # NO (the default), the class list will be sorted only by class name, # not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the # alphabetical list. # The default value is: NO. SORT_BY_SCOPE_NAME = NO # If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to # do proper type resolution of all parameters of a function it will reject a # match between the prototype and the implementation of a member function even # if there is only one candidate or it is obvious which candidate to choose # by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen # will still accept a match between prototype and implementation in such cases. # The default value is: NO. STRICT_PROTO_MATCHING = NO # The GENERATE_TODOLIST tag can be used to enable (YES) or # disable (NO) the todo list. This list is created by putting \todo # commands in the documentation. # The default value is: YES. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable (YES) or # disable (NO) the test list. This list is created by putting \test # commands in the documentation. # The default value is: YES. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable (YES) or # disable (NO) the bug list. This list is created by putting \bug # commands in the documentation. # The default value is: YES. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or # disable (NO) the deprecated list. This list is created by putting # \deprecated commands in the documentation. # The default value is: YES. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional # documentation sections, marked by \if sectionname ... \endif. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines # the initial value of a variable or macro consists of for it to appear in # the documentation. If the initializer consists of more lines than specified # here it will be hidden. Use a value of 0 to hide initializers completely. # The appearance of the initializer of individual variables and macros in the # documentation can be controlled using \showinitializer or \hideinitializer # command in the documentation regardless of this setting. # Minimum value: 0, maximum value: 10000, default value: 30. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated # at the bottom of the documentation of classes and structs. If set to YES the # list will mention the files that were used to generate the documentation. # The default value is: YES. SHOW_USED_FILES = YES # Set the SHOW_FILES tag to NO to disable the generation of the Files page. # This will remove the Files entry from the Quick Index and from the # Folder Tree View (if specified). # The default value is: YES. SHOW_FILES = YES # Set the SHOW_NAMESPACES tag to NO to disable the generation of the # Namespaces page. # This will remove the Namespaces entry from the Quick Index # and from the Folder Tree View (if specified). # The default value is: YES. SHOW_NAMESPACES = YES # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from # the version control system). Doxygen will invoke the program by executing (via # popen()) the command , where is the value of # the FILE_VERSION_FILTER tag, and is the name of an input file # provided by doxygen. Whatever the program writes to standard output # is used as the file version. See the manual for examples. FILE_VERSION_FILTER = # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed # by doxygen. The layout file controls the global structure of the generated # output files in an output format independent way. To create the layout file # that represents doxygen's defaults, run doxygen with the -l option. # You can optionally specify a file name after the option, if omitted # DoxygenLayout.xml will be used as the name of the layout file. # # Note that if you run doxygen from a directory containing a file # called DoxygenLayout.xml, doxygen will parse it automatically even # if the LAYOUT_FILE tag is left empty. LAYOUT_FILE = # The CITE_BIB_FILES tag can be used to specify one or more bib files # containing the references data. This must be a list of .bib files. The # .bib extension is automatically appended if omitted. Using this command # requires the bibtex tool to be installed. See also # http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style # of the bibliography can be controlled using LATEX_BIB_STYLE. To use this # feature you need bibtex and perl available in the search path. CITE_BIB_FILES = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated # by doxygen. Possible values are YES and NO. If left blank NO is used. # The default value is: NO. QUIET = YES # The WARNINGS tag can be used to turn on/off the warning messages that are # generated by doxygen. Possible values are YES and NO. If left blank # NO is used. # # Tip: Turn warnings on while writing the documentation. # The default value is: YES. WARNINGS = YES # If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings # for undocumented members. If EXTRACT_ALL is set to YES then this flag will # automatically be disabled. # The default value is: YES. WARN_IF_UNDOCUMENTED = YES # If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some # parameters in a documented function, or documenting parameters that # don't exist or using markup commands wrongly. # The default value is: YES. WARN_IF_DOC_ERROR = YES # The WARN_NO_PARAMDOC option can be enabled to get warnings for # functions that are documented, but have no documentation for their parameters # or return value. If set to NO (the default) doxygen will only warn about # wrong or incomplete parameter documentation, but not about the absence of # documentation. # The default value is: NO. WARN_NO_PARAMDOC = NO # The WARN_FORMAT tag determines the format of the warning messages that # doxygen can produce. The string should contain the $file, $line, and $text # tags, which will be replaced by the file and line number from which the # warning originated and the warning text. Optionally the format may contain # $version, which will be replaced by the version of the file (if it could # be obtained via FILE_VERSION_FILTER) # The default value is: $file:$line: $text. WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning # and error messages should be written. If left blank the output is written # to stderr. WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag can be used to specify the files and/or directories that contain # documented source files. You may enter file names like "myfile.cpp" or # directories like "/usr/src/myproject". Separate the files or directories # with spaces. # Note: If this tag is empty the current directory is searched. INPUT = ../src/bin/d2 \ ../src/bin/dhcp4 \ ../src/bin/dhcp6 \ ../src/bin/perfdhcp \ ../src/bin/sockcreator \ ../src/bin/lfc \ ../src/hooks/dhcp/user_chk \ ../src/lib/asiodns \ ../src/lib/asiolink \ ../src/lib/cc \ ../src/lib/cfgrpt \ ../src/lib/config \ ../src/lib/cryptolink \ ../src/lib/dhcp \ ../src/lib/dhcp_ddns \ ../src/lib/dhcpsrv \ ../src/lib/dhcpsrv/parsers \ ../src/lib/dns \ ../src/lib/eval \ ../src/lib/exceptions \ ../src/lib/hooks \ ../src/lib/log \ ../src/lib/log/compiler \ ../src/lib/log/interprocess \ ../src/lib/stats \ ../src/lib/testutils \ ../src/lib/util \ ../src/lib/util/encode \ ../src/lib/util/io \ ../src/lib/util/random \ ../src/lib/util/threads \ ../src/lib/util/unittests \ devel # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is # also the default input encoding. Doxygen uses libiconv (or the iconv built # into libc) for the transcoding. See http://www.gnu.org/software/libiconv for # the list of possible encodings. # The default value is: UTF-8. INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank the following patterns are tested: # *.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii, .ixx, *.ipp, *.i++, # *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, .h++, *.cs, # *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, .md, # *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, # *.qsf, *.as and *.js. FILE_PATTERNS = *.c \ *.cc \ *.h \ *.hpp \ *.dox # The RECURSIVE tag can be used to turn specify whether or not subdirectories # should be searched for input files as well. # The default value is: NO. RECURSIVE = NO # The EXCLUDE tag can be used to specify files and/or directories that should be # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. # Note that relative paths are relative to the directory from which doxygen is # run. EXCLUDE = ../src/lib/dns/master_lexer.cc \ ../src/lib/dns/rdataclass.cc \ ../src/lib/eval/lexer.cc # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded # from the input. # The default value is: NO. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. Note that the wildcards are matched # against the file with absolute path, so to exclude all test directories # for example use the pattern */test/* EXCLUDE_PATTERNS = */*-placeholder.* \ */cpp/*.py # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the # output. The symbol name can be a fully qualified name, a word, or if the # wildcard * is used, a substring. Examples: ANamespace, AClass, # AClass::ANamespace, ANamespace::*Test # # Note that the wildcards are matched against the file with absolute # path, so to exclude all test directories use the pattern */test/* EXCLUDE_SYMBOLS = # The EXAMPLE_PATH tag can be used to specify one or more files or # directories that contain example code fragments that are included (see # the \include command). EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank all files are included. EXAMPLE_PATTERNS = # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude # commands irrespective of the value of the RECURSIVE tag. # The default value is: NO. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or # directories that contain image that are included in the documentation (see # the \image command). IMAGE_PATH = ../doc/images ../src/lib/hooks/images ../src/bin/d2/images ../src/lib/dhcpsrv/images # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command , where # is the value of the INPUT_FILTER tag, and is the name of an # input file. Doxygen will then use the output that the filter program writes # to standard output. # If FILTER_PATTERNS is specified, this tag will be # ignored. # # Note that the filter must not add or remove lines; it is applied # before the code is scanned, but not when the output code is # generated. If lines are added or removed, the anchors will not be # placed correctly. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. # Doxygen will compare the file name with each pattern and apply the # filter if there is a match. # The filters are a list of the form: # pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further # info on how filters are used. If FILTER_PATTERNS is empty or if # non of the patterns match the file name, INPUT_FILTER is applied. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will be used to filter the input files when producing source # files to browse (i.e. when SOURCE_BROWSER is set to YES). # The default value is: NO. FILTER_SOURCE_FILES = NO # The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file # pattern. A pattern will override the setting for FILTER_PATTERN (if any) # and it is also possible to disable source filtering for a specific pattern # using *.ext= (so without naming a filter). This option only has effect when # FILTER_SOURCE_FILES is enabled. FILTER_SOURCE_PATTERNS = # If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that # is part of the input, its contents will be placed on the main page # (index.html). This can be useful if you have a project on for instance GitHub # and want to reuse the introduction page also for the doxygen output. USE_MDFILE_AS_MAINPAGE = #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will # be generated. Documented entities will be cross-referenced with these sources. # Note: To get rid of all source code in the generated output, make sure also # VERBATIM_HEADERS is set to NO. # The default value is: NO. SOURCE_BROWSER = YES # Setting the INLINE_SOURCES tag to YES will include the body # of functions and classes directly in the documentation. # The default value is: NO. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct # doxygen to hide any special comment blocks from generated source code # fragments. Normal C, C++ and Fortran comments will always remain visible. # The default value is: YES. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES # then for each documented function all documented # functions referencing it will be listed. # The default value is: NO. REFERENCED_BY_RELATION = YES # If the REFERENCES_RELATION tag is set to YES # then for each documented function all documented entities # called/used by that function will be listed. # The default value is: NO. REFERENCES_RELATION = YES # If the REFERENCES_LINK_SOURCE tag is set to YES (the default) # and SOURCE_BROWSER tag is set to YES, then the hyperlinks from # functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will # link to the source code. # Otherwise they will link to the documentation. # The default value is: YES. REFERENCES_LINK_SOURCE = YES # If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the # source code will show a tooltip with additional information such as prototype, # brief description and links to the definition and documentation. Since this # will make the HTML file larger and loading of large files a bit slower, you # can opt to disable this feature. # The default value is: YES. # This tag requires that the tag SOURCE_BROWSER is set to YES. SOURCE_TOOLTIPS = YES # If the USE_HTAGS tag is set to YES then the references to source code # will point to the HTML generated by the htags(1) tool instead of doxygen # built-in source browser. The htags tool is part of GNU's global source # tagging system (see http://www.gnu.org/software/global/global.html). You # will need version 4.8.6 or higher. # # To use it do the following: # - Install the latest version of global # - Enable SOURCE_BROWSER and USE_HTAGS in the config file # - Make sure the INPUT points to the root of the source tree # - Run doxygen as normal # # Doxygen will invoke htags (and that will in turn invoke gtags), so these # tools must be available from the command line (i.e. in the search path). # # The result: instead of the source browser generated by doxygen, the links to # source code will now point to the output of htags. # The default value is: NO. # This tag requires that the tag SOURCE_BROWSER is set to YES. USE_HTAGS = NO # If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen # will generate a verbatim copy of the header file for each class for # which an include is specified. Set to NO to disable this. # The default value is: YES. VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index # of all compounds will be generated. Enable this if the project # contains a lot of classes, structs, unions or interfaces. # The default value is: YES. ALPHABETICAL_INDEX = YES # If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then # the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns # in which this list will be split. # Minimum value: 1, maximum value: 20, default value: 5. # This tag requires that the tag ALPHABETICAL_INDEX is set to YES. COLS_IN_ALPHA_INDEX = 2 # In case all classes in a project start with a common prefix, all # classes will be put under the same header in the alphabetical index. # The IGNORE_PREFIX tag can be used to specify one or more prefixes that # should be ignored while generating the index headers. # This tag requires that the tag ALPHABETICAL_INDEX is set to YES. IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES Doxygen will generate HTML output. # The default value is: YES. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. # The default directory is: html. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_OUTPUT = ../html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for # each generated HTML page (for example: .htm,.php,.asp). # The default value is: .html. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a personal HTML header for # each generated HTML page. If it is left blank doxygen will generate a # standard header. Note that when using a custom header you are responsible # for the proper inclusion of any scripts and style sheets that doxygen # needs, which is dependent on the configuration options used. # It is advised to generate a default header using "doxygen -w html # header.html footer.html stylesheet.css YourConfigFile" and then modify # that header. Note that the header is subject to change so you typically # have to redo this when upgrading to a newer version of doxygen or when # changing the value of configuration settings such as GENERATE_TREEVIEW! # This tag requires that the tag GENERATE_HTML is set to YES. HTML_HEADER = # The HTML_FOOTER tag can be used to specify a personal HTML footer for # each generated HTML page. If it is left blank doxygen will generate a # standard footer. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading # style sheet that is used by each HTML page. It can be used to # fine-tune the look of the HTML output. If left blank doxygen will # generate a default style sheet. Note that it is recommended to use # HTML_EXTRA_STYLESHEET instead of this one, as it is more robust and this # tag will in the future become obsolete. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_STYLESHEET = # The HTML_EXTRA_STYLESHEET tag can be used to specify an additional # user-defined cascading style sheet that is included after the standard # style sheets created by doxygen. Using this option one can overrule # certain style aspects. This is preferred over using HTML_STYLESHEET # since it does not replace the standard style sheet and is therefor more # robust against future updates. Doxygen will copy the style sheet file to # the output directory. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_EXTRA_STYLESHEET = # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the HTML output directory. Note # that these files will be copied to the base HTML output directory. Use the # $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these # files. In the HTML_STYLESHEET file, use the file name only. Also note that # the files will be copied as-is; there are no commands or markers available. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_EXTRA_FILES = # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. # Doxygen will adjust the colors in the style sheet and background images # according to this color. Hue is specified as an angle on a colorwheel, # see http://en.wikipedia.org/wiki/Hue for more information. # For instance the value 0 represents red, 60 is yellow, 120 is green, # 180 is cyan, 240 is blue, 300 purple, and 360 is red again. # Minimum value: 0, maximum value: 359, default value: 220. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_HUE = 220 # The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of # the colors in the HTML output. For a value of 0 the output will use # grayscales only. A value of 255 will produce the most vivid colors. # Minimum value: 0, maximum value: 255, default value: 100. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_SAT = 100 # The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to # the luminance component of the colors in the HTML output. Values below # 100 gradually make the output lighter, whereas values above 100 make # the output darker. The value divided by 100 is the actual gamma applied, # so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, # and 100 does not change the gamma. # Minimum value: 40, maximum value: 240, default value: 80. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_GAMMA = 80 # If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML # page will contain the date and time when the page was generated. Setting # this to NO can help when comparing the output of multiple runs. # The default value is: YES. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_TIMESTAMP = YES # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the # page has loaded. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_DYNAMIC_SECTIONS = YES # With HTML_INDEX_NUM_ENTRIES one can control the preferred number of # entries shown in the various tree structured indices initially; the user # can expand and collapse entries dynamically later on. Doxygen will expand # the tree to such a level that at most the specified number of entries are # visible (unless a fully collapsed tree already exceeds this amount). # So setting the number of entries 1 will produce a full collapsed tree by # default. 0 is a special value representing an infinite number of entries # and will result in a full expanded tree by default. # Minimum value: 0, maximum value: 9999, default value: 100. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_INDEX_NUM_ENTRIES = 100 # If the GENERATE_DOCSET tag is set to YES, additional index files # will be generated that can be used as input for Apple's Xcode 3 # integrated development environment, introduced with OSX 10.5 (Leopard). # To create a documentation set, doxygen will generate a Makefile in the # HTML output directory. Running make will produce the docset in that # directory and running "make install" will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find # it at startup. # See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html # for more information. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_DOCSET = NO # When GENERATE_DOCSET tag is set to YES, this tag determines the name of the # feed. A documentation feed provides an umbrella under which multiple # documentation sets from a single provider (such as a company or product suite) # can be grouped. # The default value is: Doxygen generated docs. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_FEEDNAME = "Doxygen generated docs" # When GENERATE_DOCSET tag is set to YES, this tag specifies a string that # should uniquely identify the documentation set bundle. This should be a # reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen # will append .docset to the name. # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_BUNDLE_ID = org.doxygen.Project # When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely # identify the documentation publisher. This should be a reverse domain-name # style string, e.g. com.mycompany.MyDocSet.documentation. # The default value is: org.doxygen.Publisher. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_PUBLISHER_ID = org.doxygen.Publisher # The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. # The default value is: Publisher. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_PUBLISHER_NAME = Publisher # If the GENERATE_HTMLHELP tag is set to YES, additional index files # will be generated that can be used as input for tools like the # Microsoft HTML help workshop to generate a compiled HTML help file (.chm) # of the generated HTML documentation. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_HTMLHELP = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can # be used to specify the file name of the resulting .chm file. You # can add a path in front of the file if the result should not be # written to the html output directory. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. CHM_FILE = # If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can # be used to specify the location (absolute path including file name) of # the HTML help compiler (hhc.exe). If non-empty doxygen will try to run # the HTML help compiler on the generated index.hhp. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. HHC_LOCATION = # If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag # controls if a separate .chi index file is generated (YES) or that # it should be included in the master .chm file (NO). # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. GENERATE_CHI = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING # is used to encode HtmlHelp index (hhk), content (hhc) and project file # content. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. CHM_INDEX_ENCODING = # If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag # controls whether a binary table of contents is generated (YES) or a # normal table of contents (NO) in the .chm file. # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members # to the contents of the HTML help documentation and to the tree view. # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. TOC_EXPAND = NO # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and # QHP_VIRTUAL_FOLDER are set, an additional index file will be generated # that can be used as input for Qt's qhelpgenerator to generate a # Qt Compressed Help (.qch) of the generated HTML documentation. # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. GENERATE_QHP = NO # If the QHG_LOCATION tag is specified, the QCH_FILE tag can # be used to specify the file name of the resulting .qch file. # The path specified is relative to the HTML output folder. # This tag requires that the tag GENERATE_QHP is set to YES. QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating # Qt Help Project output. For more information please see # http://doc.trolltech.com/qthelpproject.html#namespace # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_QHP is set to YES. QHP_NAMESPACE = # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating # Qt Help Project output. For more information please see # http://doc.trolltech.com/qthelpproject.html#virtual-folders # The default value is: doc. # This tag requires that the tag GENERATE_QHP is set to YES. QHP_VIRTUAL_FOLDER = doc # If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to # add. For more information please see # http://doc.trolltech.com/qthelpproject.html#custom-filters # This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_NAME = # The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the # custom filter to add. For more information please see # # Qt Help Project / Custom Filters. # This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_ATTRS = # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this # project's # filter section matches. # # Qt Help Project / Filter Attributes. # This tag requires that the tag GENERATE_QHP is set to YES. QHP_SECT_FILTER_ATTRS = # If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can # be used to specify the location of Qt's qhelpgenerator. # If non-empty doxygen will try to run qhelpgenerator on the generated # .qhp file. # This tag requires that the tag GENERATE_QHP is set to YES. QHG_LOCATION = # If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files # will be generated, which together with the HTML files, form an Eclipse help # plugin. To install this plugin and make it available under the help contents # menu in Eclipse, the contents of the directory containing the HTML and XML # files needs to be copied into the plugins directory of eclipse. The name of # the directory within the plugins directory should be the same as # the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before # the help appears. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_ECLIPSEHELP = NO # A unique identifier for the eclipse help plugin. When installing the plugin # the directory name containing the HTML and XML files should also have # this name. # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. ECLIPSE_DOC_ID = org.doxygen.Project # The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) # at top of each HTML page. The value NO (the default) enables the index and # the value YES disables it. Since the tabs have the same information as the # navigation tree you can set this option to NO if you already set # GENERATE_TREEVIEW to YES. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. DISABLE_INDEX = NO # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index # structure should be generated to display hierarchical information. # If the tag value is set to YES, a side panel will be generated # containing a tree-like index structure (just like the one that # is generated for HTML Help). For this to work a browser that supports # JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). # Windows users are probably better off using the HTML help feature. # Since the tree basically has the same information as the tab index you # could consider to set DISABLE_INDEX to NO when enabling this option. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_TREEVIEW = YES # The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values # (range [0,1..20]) that doxygen will group on one line in the generated HTML # documentation. Note that a value of 0 will completely suppress the enum # values from appearing in the overview section. # Minimum value: 0, maximum value: 20, default value: 4. # This tag requires that the tag GENERATE_HTML is set to YES. ENUM_VALUES_PER_LINE = 4 # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be # used to set the initial width (in pixels) of the frame in which the tree # is shown. # Minimum value: 0, maximum value: 1500, default value: 250. # This tag requires that the tag GENERATE_HTML is set to YES. TREEVIEW_WIDTH = 180 # When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open # links to external symbols imported via tag files in a separate window. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. EXT_LINKS_IN_WINDOW = NO # Use this tag to change the font size of Latex formulas included # as images in the HTML documentation. The default is 10. Note that # when you change the font size after a successful doxygen run you need # to manually remove any form_*.png images from the HTML output directory # to force them to be regenerated. # Minimum value: 8, maximum value: 50, default value: 10. # This tag requires that the tag GENERATE_HTML is set to YES. FORMULA_FONTSIZE = 10 # Use the FORMULA_TRANPARENT tag to determine whether or not the images # generated for formulas are transparent PNGs. Transparent PNGs are # not supported properly for IE 6.0, but are supported on all modern browsers. # Note that when changing this option you need to delete any form_*.png files # in the HTML output before the changes have effect. # The default value is: YES. # This tag requires that the tag GENERATE_HTML is set to YES. FORMULA_TRANSPARENT = YES # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax # (see http://www.mathjax.org) which uses client side Javascript for the # rendering instead of using prerendered bitmaps. Use this if you do not # have LaTeX installed or if you want to formulas look prettier in the HTML # output. When enabled you may also need to install MathJax separately and # configure the path to it using the MATHJAX_RELPATH option. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. USE_MATHJAX = NO # When MathJax is enabled you can set the default output format to be used for # the MathJax output. See the MathJax site (see: # http://docs.mathjax.org/en/latest/output.html) for more details. # Possible values are: HTML-CSS (which is slower, but has the best # compatibility), NativeMML (i.e. MathML) and SVG. # The default value is: HTML-CSS. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_FORMAT = HTML-CSS # When MathJax is enabled you need to specify the location relative to the # HTML output directory using the MATHJAX_RELPATH option. The destination # directory should contain the MathJax.js script. For instance, if the mathjax # directory is located at the same level as the HTML output directory, then # MATHJAX_RELPATH should be ../mathjax. The default value points to # the MathJax Content Delivery Network so you can quickly see the result without # installing MathJax. # However, it is strongly recommended to install a local # copy of MathJax from http://www.mathjax.org before deployment. # The default value is: http://cdn.mathjax.org/mathjax/latest. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest # The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension # names that should be enabled during MathJax rendering. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_EXTENSIONS = # The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces # of code that will be used on startup of the MathJax code. See the MathJax site # (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an # example see the documentation. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_CODEFILE = # When the SEARCHENGINE tag is enabled doxygen will generate a search box # for the HTML output. The underlying search engine uses javascript # and DHTML and should work on any modern browser. Note that when using # HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets # (GENERATE_DOCSET) there is already a search function so this one should # typically be disabled. For large projects the javascript based search engine # can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. # The default value is: YES. # This tag requires that the tag GENERATE_HTML is set to YES. SEARCHENGINE = NO # When the SERVER_BASED_SEARCH tag is enabled the search engine will be # implemented using a PHP enabled web server instead of at the web client # using Javascript. Doxygen will generate the search PHP script and index # file to put on the web server. The advantage of the server # based approach is that it scales better to large projects and allows # full text search. The disadvantages are that it is more difficult to setup # and does not have live searching capabilities. # The default value is: NO. # This tag requires that the tag SEARCHENGINE is set to YES. SERVER_BASED_SEARCH = NO # When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP # script for searching. Instead the search results are written to an XML file # which needs to be processed by an external indexer. Doxygen will invoke an # external search engine pointed to by the SEARCHENGINE_URL option to obtain the # search results. # # Doxygen ships with an example indexer ( doxyindexer) and search engine # (doxysearch.cgi) which are based on the open source search engine library # Xapian (see: http://xapian.org/). # # See the section "External Indexing and Searching" for details. # The default value is: NO. # This tag requires that the tag SEARCHENGINE is set to YES. EXTERNAL_SEARCH = NO # The SEARCHENGINE_URL should point to a search engine hosted by a web server # which will return the search results when EXTERNAL_SEARCH is enabled. # # Doxygen ships with an example indexer ( doxyindexer) and search engine # (doxysearch.cgi) which are based on the open source search engine library # Xapian (see: http://xapian.org/). See the section "External Indexing and # Searching" for details. # This tag requires that the tag SEARCHENGINE is set to YES. SEARCHENGINE_URL = # When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed # search data is written to a file for indexing by an external tool. With the # SEARCHDATA_FILE tag the name of this file can be specified. # The default file is: searchdata.xml. # This tag requires that the tag SEARCHENGINE is set to YES. SEARCHDATA_FILE = searchdata.xml # When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the # EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is # useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple # projects and redirect the results back to the right project. # This tag requires that the tag SEARCHENGINE is set to YES. EXTERNAL_SEARCH_ID = # The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen # projects other than the one defined by this configuration file, but that are # all added to the same external search index. Each project needs to have a # unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of # to a relative location where the documentation can be found. The format is: # EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ... # This tag requires that the tag SEARCHENGINE is set to YES. EXTRA_SEARCH_MAPPINGS = #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- # If the GENERATE_LATEX tag is set to YES Doxygen will generate Latex output. # The default value is: YES. GENERATE_LATEX = NO # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. # The default directory is: latex. # This tag requires that the tag GENERATE_LATEX is set to YES. LATEX_OUTPUT = latex # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. If left blank `latex' will be used as the default command name. # Note that when enabling USE_PDFLATEX this option is only used for # generating bitmaps for formulas in the HTML output, but not in the # Makefile that is written to the output directory. # The default file is: latex. # This tag requires that the tag GENERATE_LATEX is set to YES. LATEX_CMD_NAME = latex # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to # generate index for LaTeX. # The default file is: makeindex. # This tag requires that the tag GENERATE_LATEX is set to YES. MAKEINDEX_CMD_NAME = makeindex # If the COMPACT_LATEX tag is set to YES Doxygen generates more compact # LaTeX documents. This may be useful for small projects and may help to # save some trees in general. # The default value is: NO. # This tag requires that the tag GENERATE_LATEX is set to YES. COMPACT_LATEX = NO # The PAPER_TYPE tag can be used to set the paper type that is used # by the printer. Possible values are: a4, letter, legal and # executive. # The default value is: a4. # This tag requires that the tag GENERATE_LATEX is set to YES. PAPER_TYPE = a4wide # The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX # packages that should be included in the LaTeX output. # If left blank no extra packages will be included. # This tag requires that the tag GENERATE_LATEX is set to YES. EXTRA_PACKAGES = # The LATEX_HEADER tag can be used to specify a personal LaTeX header for # the generated latex document. The header should contain everything until # the first chapter. If it is left blank doxygen will generate a # standard header. Notice: only use this tag if you know what you are doing! # This tag requires that the tag GENERATE_LATEX is set to YES. LATEX_HEADER = # The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for # the generated latex document. The footer should contain everything after # the last chapter. If it is left blank doxygen will generate a # standard footer. Notice: only use this tag if you know what you are doing! # This tag requires that the tag GENERATE_LATEX is set to YES. LATEX_FOOTER = # The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined # LaTeX style sheets that are included after the standard style sheets created # by doxygen. Using this option one can overrule certain style aspects. Doxygen # will copy the style sheet files to the output directory. # Note: The order of the extra style sheet files is of importance # (e.g. the last style sheet in the list overrules the setting of the # previous ones in the list). # This tag requires that the tag GENERATE_LATEX is set to YES. # XXX Only in 1.8.10 #LATEX_EXTRA_STYLESHEET = # The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the LATEX_OUTPUT output # directory. Note that the files will be copied as-is; there are no commands or # markers available. # This tag requires that the tag GENERATE_LATEX is set to YES. LATEX_EXTRA_FILES = # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated # is prepared for conversion to pdf (using ps2pdf). The pdf file will # contain links (just like the HTML output) instead of page references # This makes the output suitable for online browsing using a pdf viewer. # The default value is: YES. # This tag requires that the tag GENERATE_LATEX is set to YES. PDF_HYPERLINKS = NO # If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of # plain latex in the generated Makefile. Set this option to YES to get a # higher quality PDF documentation. # The default value is: YES. # This tag requires that the tag GENERATE_LATEX is set to YES. USE_PDFLATEX = NO # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. # command to the generated LaTeX files. This will instruct LaTeX to keep # running if errors occur, instead of asking the user for help. # This option is also used when generating formulas in HTML. # The default value is: NO. # This tag requires that the tag GENERATE_LATEX is set to YES. LATEX_BATCHMODE = NO # If LATEX_HIDE_INDICES is set to YES then doxygen will not # include the index chapters (such as File Index, Compound Index, etc.) # in the output. # The default value is: NO. # This tag requires that the tag GENERATE_LATEX is set to YES. LATEX_HIDE_INDICES = NO # If LATEX_SOURCE_CODE is set to YES then doxygen will include # source code with syntax highlighting in the LaTeX output. # Note that which sources are shown also depends on other settings # such as SOURCE_BROWSER. # The default value is: NO. # This tag requires that the tag GENERATE_LATEX is set to YES. LATEX_SOURCE_CODE = NO # The LATEX_BIB_STYLE tag can be used to specify the style to use for the # bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See # http://en.wikipedia.org/wiki/BibTeX for more info. # The default value is: plain. # This tag requires that the tag GENERATE_LATEX is set to YES. LATEX_BIB_STYLE = plain #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- # If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output # The RTF output is optimized for Word 97 and may not look very pretty with # other RTF readers or editors. # The default value is: NO. GENERATE_RTF = NO # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `rtf' will be used as the default path. # The default directory is: rtf. # This tag requires that the tag GENERATE_RTF is set to YES. RTF_OUTPUT = rtf # If the COMPACT_RTF tag is set to YES Doxygen generates more compact # RTF documents. This may be useful for small projects and may help to # save some trees in general. # The default value is: NO. # This tag requires that the tag GENERATE_RTF is set to YES. COMPACT_RTF = NO # If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated # will contain hyperlink fields. The RTF file will # contain links (just like the HTML output) instead of page references. # This makes the output suitable for online browsing using WORD or other # programs which support those fields. # Note: wordpad (write) and others do not support links. # The default value is: NO. # This tag requires that the tag GENERATE_RTF is set to YES. RTF_HYPERLINKS = NO # Load style sheet definitions from file. Syntax is similar to doxygen's # config file, i.e. a series of assignments. You only have to provide # replacements, missing definitions are set to their default value. # This tag requires that the tag GENERATE_RTF is set to YES. RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an rtf document. # Syntax is similar to doxygen's config file. # This tag requires that the tag GENERATE_RTF is set to YES. RTF_EXTENSIONS_FILE = # If the RTF_SOURCE_CODE tag is set to YES then doxygen will include # source code with syntax highlighting in the RTF output. # # Note that which sources are shown also depends on other settings such as # SOURCE_BROWSER. # The default value is: NO. # This tag requires that the tag GENERATE_RTF is set to YES. # XXX Only in 1.8.10 #RTF_SOURCE_CODE = NO #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- # If the GENERATE_MAN tag is set to YES Doxygen will generate man pages for # classes and files. # The default value is: NO. GENERATE_MAN = NO # The MAN_OUTPUT tag is used to specify where the man pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. # The default directory is: man. # This tag requires that the tag GENERATE_MAN is set to YES. MAN_OUTPUT = man # The MAN_EXTENSION tag determines the extension that is added to # the generated man pages (default is the subroutine's section .3) # The default value is: .3. # This tag requires that the tag GENERATE_MAN is set to YES. MAN_EXTENSION = .3 # The MAN_SUBDIR tag determines the name of the directory created within # MAN_OUTPUT in which the man pages are placed. If defaults to man followed by # MAN_EXTENSION with the initial . removed. # This tag requires that the tag GENERATE_MAN is set to YES. # XXX Only in 1.8.10 #MAN_SUBDIR = # If the MAN_LINKS tag is set to YES and Doxygen generates man output, # then it will generate one additional man file for each entity # documented in the real man page(s). These additional files # only source the real man page, but without them the man command # would be unable to find the correct page. The default is NO. # The default value is: NO. # This tag requires that the tag GENERATE_MAN is set to YES. MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- # If the GENERATE_XML tag is set to YES Doxygen will # generate an XML file that captures the structure of # the code including all documentation. # The default value is: NO. GENERATE_XML = NO # The XML_OUTPUT tag is used to specify where the XML pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `xml' will be used as the default path. # The default directory is: xml. # This tag requires that the tag GENERATE_XML is set to YES. XML_OUTPUT = xml # The XML_SCHEMA tag can be used to specify an XML schema, # which can be used by a validating XML parser to check the # syntax of the XML files. # This tag requires that the tag GENERATE_XML is set to YES. # XXX Obsolete in 1.8.10 #XML_SCHEMA = # The XML_DTD tag can be used to specify an XML DTD, # which can be used by a validating XML parser to check the # syntax of the XML files. # This tag requires that the tag GENERATE_XML is set to YES. # XXX Obsolete in 1.8.10 #XML_DTD = # If the XML_PROGRAMLISTING tag is set to YES Doxygen will # dump the program listings (including syntax highlighting # and cross-referencing information) to the XML output. Note that # enabling this will significantly increase the size of the XML output. # The default value is: YES. # This tag requires that the tag GENERATE_XML is set to YES. XML_PROGRAMLISTING = NO #--------------------------------------------------------------------------- # Configuration options related to the DOCBOOK output #--------------------------------------------------------------------------- # If the GENERATE_DOCBOOK tag is set to YES doxygen will generate Docbook files # that can be used to generate PDF. # The default value is: NO. GENERATE_DOCBOOK = NO # The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be put in # front of it. # The default directory is: docbook. # This tag requires that the tag GENERATE_DOCBOOK is set to YES. DOCBOOK_OUTPUT = docbook # If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will # include the program listings (including syntax highlighting and # cross-referencing information) to the DOCBOOK output. Note that # enabling this will significantly increase the size of the DOCBOOK # output. # The default value is: NO. # This tag requires that the tag GENERATE_DOCBOOK is set to YES. # XXX Only in 1.8.10 #DOCBOOK_PROGRAMLISTING = NO #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will # generate an AutoGen Definitions (see autogen.sf.net) file # that captures the structure of the code including all # documentation. Note that this feature is still experimental # and incomplete at the moment. # The default value is: NO. GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- # If the GENERATE_PERLMOD tag is set to YES Doxygen will # generate a Perl module file that captures the structure of # the code including all documentation. Note that this # feature is still experimental and incomplete at the # moment. # The default value is: NO. GENERATE_PERLMOD = NO # If the PERLMOD_LATEX tag is set to YES Doxygen will generate # the necessary Makefile rules, Perl scripts and LaTeX code to be able # to generate PDF and DVI output from the Perl module output. # The default value is: NO. # This tag requires that the tag GENERATE_PERLMOD is set to YES. PERLMOD_LATEX = NO # If the PERLMOD_PRETTY tag is set to YES the Perl module output will be # nicely formatted so it can be parsed by a human reader. # This is useful # if you want to understand what is going on. # On the other hand, if this # tag is set to NO the size of the Perl module output will be much smaller # and Perl will parse it just the same. # The default value is: YES. # This tag requires that the tag GENERATE_PERLMOD is set to YES. PERLMOD_PRETTY = YES # The names of the make variables in the generated doxyrules.make file # are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. # This is useful so different doxyrules.make files included by the same # Makefile don't overwrite each other's variables. # This tag requires that the tag GENERATE_PERLMOD is set to YES. PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- # If the ENABLE_PREPROCESSING tag is set to YES Doxygen will evaluate all # C-preprocessor directives found in the sources and include files. # The default value is: YES. ENABLE_PREPROCESSING = YES # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all # macro names in the source code. If set to NO only conditional # compilation will be performed. Macro expansion can be done in a # controlled way by setting EXPAND_ONLY_PREDEF to YES. # The default value is: NO. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. MACRO_EXPANSION = YES # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES # then the macro expansion is limited to the macros specified with the # PREDEFINED and EXPAND_AS_DEFINED tags. # The default value is: NO. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. EXPAND_ONLY_PREDEF = NO # If the SEARCH_INCLUDES tag is set to YES the includes files in the # INCLUDE_PATH will be searched if a #include is found. # The default value is: YES. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by # the preprocessor. # This tag requires that the tag SEARCH_INCLUDES is set to YES. INCLUDE_PATH = # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the # directories. If left blank, the patterns specified with FILE_PATTERNS will # be used. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. INCLUDE_FILE_PATTERNS = # The PREDEFINED tag can be used to specify one or more macro names that # are defined before the preprocessor is started (similar to the -D option of # gcc). The argument of the tag is a list of macros of the form: name # or name=definition (no spaces). If the definition and the = are # omitted =1 is assumed. To prevent a macro definition from being # undefined via #undef or recursively expanded use the := operator # instead of the = operator. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. PREDEFINED = # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. # The macro definition that is found in the sources will be used. # Use the PREDEFINED tag if you want to use a different macro definition that # overrules the definition found in the source code. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's # preprocessor will remove all references to function-like macros that # are alone on a line, have an all uppercase name, and do not end with # a semicolon, because these will confuse the parser if not removed. # The default value is: YES. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- # The TAGFILES option can be used to specify one or more tagfiles. For each # tag file the location of the external documentation should be added. The # format of a tag file without this location is as follows: # # TAGFILES = file1 file2 ... # Adding location for the tag files is done as follows: # # TAGFILES = file1=loc1 "file2 = loc2" ... # where "loc1" and "loc2" can be relative or absolute paths # or URLs. Note that each tag file must have a unique name (where the name does # NOT include the path). If a tag file is not located in the directory in which # doxygen is run, you must also specify the path to the tagfile here. TAGFILES = # When a file name is specified after GENERATE_TAGFILE, doxygen will create # a tag file that is based on the input files it reads. GENERATE_TAGFILE = # If the ALLEXTERNALS tag is set to YES all external classes will be listed # in the class index. If set to NO only the inherited external classes # will be listed. # The default value is: NO. ALLEXTERNALS = NO # If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed # in the modules index. If set to NO, only the current project's groups will # be listed. # The default value is: YES. EXTERNAL_GROUPS = YES # If the EXTERNAL_PAGES tag is set to YES all external pages will be listed in # the related pages index. If set to NO, only the current project's pages will # be listed. # The default value is: YES. EXTERNAL_PAGES = YES # The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of `which perl'). # The default file (with absolute path) is: /usr/bin/perl. PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- # If the CLASS_DIAGRAMS tag is set to YES Doxygen will generate a # inheritance diagram (in HTML, RTF and LaTeX) for classes with base # or super classes. Setting the tag to NO turns the diagrams off. Note # that this option also works with HAVE_DOT disabled, but it is # recommended to install and use dot, since it yields more powerful # graphs. # The default value is: YES. CLASS_DIAGRAMS = YES # You can define message sequence charts within doxygen comments using the \msc # command. Doxygen will then run the mscgen tool (see # http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the # documentation. The MSCGEN_PATH tag allows you to specify the directory where # the mscgen tool resides. If left empty the tool is assumed to be found in the # default search path. MSCGEN_PATH = # If set to YES, the inheritance and collaboration graphs will hide # inheritance and usage relations if the target is undocumented # or is not a class. # The default value is: YES. HIDE_UNDOC_RELATIONS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz, a graph visualization # toolkit from AT&T and Lucent Bell Labs. The other options in this section # have no effect if this option is set to NO # The default value is: NO. HAVE_DOT = NO # The DOT_NUM_THREADS specifies the number of dot invocations doxygen # is allowed to run in parallel. When set to 0 doxygen will base this # on the number of processors available in the system. You can set it # explicitly to a value larger than 0 to get control over the balance # between CPU load and processing speed. # Minimum value: 0, maximum value: 32, default value: 0. # This tag requires that the tag HAVE_DOT is set to YES. DOT_NUM_THREADS = 0 # When you want a differently looking font you can specify the font # name using DOT_FONTNAME. You need to make sure dot is able to find # the font, which can be done by putting it in a standard location or # by setting the DOTFONTPATH environment variable or by setting # DOT_FONTPATH to the directory containing the font. # The default value is: Helvetica. # This tag requires that the tag HAVE_DOT is set to YES. #DOT_FONTNAME = FreeSans # The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. # Minimum value: 4, maximum value: 24, default value: 10. # This tag requires that the tag HAVE_DOT is set to YES. #DOT_FONTSIZE = 10 # By default doxygen will tell dot to use the Helvetica font. # If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to # set the path where dot can find it. # This tag requires that the tag HAVE_DOT is set to YES. #DOT_FONTPATH = # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect inheritance relations. Setting this tag to YES will force the # CLASS_DIAGRAMS tag to NO. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. CLASS_GRAPH = YES # If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect implementation dependencies (inheritance, containment, and # class references variables) of the class with other documented classes. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. COLLABORATION_GRAPH = NO # If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen # will generate a graph for groups, showing the direct groups dependencies # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. GROUP_GRAPHS = YES # If the UML_LOOK tag is set to YES doxygen will generate inheritance and # collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. # The default value is: NO. # This tag requires that the tag HAVE_DOT is set to YES. UML_LOOK = NO # If the UML_LOOK tag is enabled, the fields and methods are shown inside # the class node. If there are many fields or methods and many nodes the # graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS # threshold limits the number of items for each type to make the size more # managable. Set this to 0 for no limit. Note that the threshold may be # exceeded by 50% before the limit is enforced. # Minimum value: 0, maximum value: 100, default value: 10. # This tag requires that the tag HAVE_DOT is set to YES. UML_LIMIT_NUM_FIELDS = 10 # If set to YES, the inheritance and collaboration graphs will show the # relations between templates and their instances. # The default value is: NO. # This tag requires that the tag HAVE_DOT is set to YES. TEMPLATE_RELATIONS = NO # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT # tags are set to YES then doxygen will generate a graph for each documented # file showing the direct and indirect include dependencies of the file with # other documented files. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. INCLUDE_GRAPH = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and # HAVE_DOT tags are set to YES then doxygen will generate a graph for each # documented header file showing the documented files that directly or # indirectly include this file. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. INCLUDED_BY_GRAPH = YES # If the CALL_GRAPH and HAVE_DOT options are set to YES then # doxygen will generate a call dependency graph for every global function # or class method. Note that enabling this option will significantly increase # the time of a run. So in most cases it will be better to enable call graphs # for selected functions only using the \callgraph command. # The default value is: NO. # This tag requires that the tag HAVE_DOT is set to YES. CALL_GRAPH = NO # If the CALLER_GRAPH and HAVE_DOT tags are set to YES then # doxygen will generate a caller dependency graph for every global function # or class method. Note that enabling this option will significantly increase # the time of a run. So in most cases it will be better to enable caller # graphs for selected functions only using the \callergraph command. # The default value is: NO. # This tag requires that the tag HAVE_DOT is set to YES. CALLER_GRAPH = NO # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen # will generate a graphical hierarchy of all classes instead of a textual one. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. GRAPHICAL_HIERARCHY = YES # If the DIRECTORY_GRAPH and HAVE_DOT tags are set to YES # then doxygen will show the dependencies a directory has on other directories # in a graphical way. The dependency relations are determined by the #include # relations between the files in the directories. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. DIRECTORY_GRAPH = YES # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. Possible values are svg, png, jpg, or gif. # If left blank png will be used. If you choose svg you need to set # HTML_FILE_EXTENSION to xhtml in order to make the SVG files # visible in IE 9+ (other browsers do not have this requirement). # Possible values are: png, jpg, gif and svg. # The default value is: png. # This tag requires that the tag HAVE_DOT is set to YES. DOT_IMAGE_FORMAT = png # If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to # enable generation of interactive SVG images that allow zooming and panning. # Note that this requires a modern browser other than Internet Explorer. # Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you # need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files # visible. Older versions of IE do not have SVG support. # The default value is: NO. # This tag requires that the tag HAVE_DOT is set to YES. INTERACTIVE_SVG = NO # The tag DOT_PATH can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found in the path. # This tag requires that the tag HAVE_DOT is set to YES. DOT_PATH = # The DOTFILE_DIRS tag can be used to specify one or more directories that # contain dot files that are included in the documentation (see the # \dotfile command). # This tag requires that the tag HAVE_DOT is set to YES. DOTFILE_DIRS = # The MSCFILE_DIRS tag can be used to specify one or more directories that # contain msc files that are included in the documentation (see the # \mscfile command). MSCFILE_DIRS = # The DIAFILE_DIRS tag can be used to specify one or more directories that # contain dia files that are included in the documentation (see the \diafile # command). DIAFILE_DIRS = # When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the # path where java can find the plantuml.jar file. If left blank, it is assumed # PlantUML is not used or called during a preprocessing step. Doxygen will # generate a warning when it encounters a \startuml command in this case and # will not generate output for the diagram. # XXX Only in 1.8.10 #PLANTUML_JAR_PATH = # When using plantuml, the specified paths are searched for files specified by # the !include statement in a plantuml block. # XXX Only in 1.8.10 #PLANTUML_INCLUDE_PATH = # The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of # nodes that will be shown in the graph. If the number of nodes in a graph # becomes larger than this value, doxygen will truncate the graph, which is # visualized by representing a node as a red box. Note that doxygen if the # number of direct children of the root node in a graph is already larger than # DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note # that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. # Minimum value: 0, maximum value: 10000, default value: 50. # This tag requires that the tag HAVE_DOT is set to YES. DOT_GRAPH_MAX_NODES = 50 # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the # graphs generated by dot. A depth value of 3 means that only nodes reachable # from the root by following a path via at most 3 edges will be shown. Nodes # that lay further from the root node will be omitted. Note that setting this # option to 1 or 2 may greatly reduce the computation time needed for large # code bases. Also note that the size of a graph can be further restricted by # DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. # Minimum value: 0, maximum value: 1000, default value: 0. # This tag requires that the tag HAVE_DOT is set to YES. MAX_DOT_GRAPH_DEPTH = 0 # Set the DOT_TRANSPARENT tag to YES to generate images with a transparent # background. This is disabled by default, because dot on Windows does not # seem to support this out of the box. Warning: Depending on the platform used, # enabling this option may lead to badly anti-aliased labels on the edges of # a graph (i.e. they become hard to read). # The default value is: NO. # This tag requires that the tag HAVE_DOT is set to YES. DOT_TRANSPARENT = NO # Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output # files in one run (i.e. multiple -o and -T options on the command line). This # makes dot run faster, but since only newer versions of dot (>1.8.10) # support this, this feature is disabled by default. # The default value is: NO. # This tag requires that the tag HAVE_DOT is set to YES. DOT_MULTI_TARGETS = NO # If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will # generate a legend page explaining the meaning of the various boxes and # arrows in the dot generated graphs. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. GENERATE_LEGEND = YES # If the DOT_CLEANUP tag is set to YES (the default) Doxygen will # remove the intermediate dot files that are used to generate # the various graphs. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. DOT_CLEANUP = YES kea-1.1.0/doc/Doxyfile-xml0000664000175000017500000000034212772017075012254 00000000000000# This is a doxygen configuration for generating XML output as well as HTML. # # Inherit everything from our default Doxyfile except GENERATE_XML, which # will be reset to YES @INCLUDE = Doxyfile GENERATE_XML = YES kea-1.1.0/doc/examples/0000775000175000017500000000000012772742653011656 500000000000000kea-1.1.0/doc/examples/ddns/0000775000175000017500000000000012772742653012606 500000000000000kea-1.1.0/doc/examples/ddns/sample1.json0000664000175000017500000000626312772017075014763 00000000000000# This is an example configuration file for D2, Kea's DHCP-DDNS processor. # It supports updating two Forward DNS zones "four.example.com" and # "six.example.com"; and one Reverse DNS zone, "2.0.192.in-addr.arpa." { # ------------------ DHCP-DDNS --------------------- # "DhcpDdns": { # -------------- Global Parameters ---------------- # # D2 will listen for update requests for Kea DHCP servers at 172.16.1.10 # on port 53001. Maximum time to we will wait for a DNS server to # respond to us is 1000 ms. "ip-address": "172.16.1.10", "port": 53001, "dns-server-timeout" : 1000, # # ----------------- Forward DDNS ------------------ # # 1. Zone - "four.example.com. # It uses TSIG, key name is "d2.md5.key" # It is served by one DNS server which listens for DDNS requests at # 172.16.1.1 on the default port 53 (standard DNS port) # # 2. Zone - "six.example.com." # It does not use TSIG. # It is server by one DNS server at "2001:db8:1::10" on port 7802 "forward-ddns": { "ddns-domains": [ # DdnsDomain for zone "four.example.com." { "name": "four.example.com.", "key-name": "d2.md5.key", "dns-servers": [ { "ip-address": "172.16.1.1" } ] }, # DdnsDomain for zone "six.example.com." { "name": "six.example.com.", "dns-servers": [ { "ip-address": "2001:db8:1::10", "port": 7802 } ] } ] }, # # ----------------- Reverse DDNS ------------------ # # We will update Reverse DNS for one zone "2.0.192.in-addr-arpa". It # uses TSIG with key "d2.sha1.key" and is served by two DNS servers: # one listening at "172.16.1.1" on 53001 and the other at "192.168.2.10". # "reverse-ddns": { "ddns-domains": [ { "name": "2.0.192.in-addr.arpa.", "key-name": "d2.sha1.key", "dns-servers": [ { "ip-address": "172.16.1.1", "port": 53001 }, { "ip-address": "192.168.2.10" } ] } ] }, # # ------------------ TSIG keys --------------------- # # Each key has a name, an algorithm (HMAC-MD5, HMAC-SHA1, HMAC-SHA224...) # and a base-64 encoded shared secret. # "tsig-keys": [ { "name": "d2.md5.key", "algorithm": "HMAC-MD5", "secret": "LSWXnfkKZjdPJI5QxlpnfQ==" }, { "name": "d2.sha1.key", "algorithm": "HMAC-SHA1", "secret": "hRrp29wzUv3uzSNRLlY68w==" }, { "name": "d2.sha512.key", "algorithm": "HMAC-SHA512", "digest-bits": 256, "secret": "/4wklkm04jeH4anx2MKGJLcya+ZLHldL5d6mK+4q6UXQP7KJ9mS2QG29hh0SJR4LA0ikxNJTUMvir42gLx6fGQ==" } ] } } kea-1.1.0/doc/examples/ddns/template.json0000664000175000017500000000516312772017075015232 00000000000000# This file may be used a template for constructing DHCP-DDNS JSON # configuration. # # Default values that may be omitted are '#' commented out. # If in a file by itself, it must start with a left-curly-bracket. { "DhcpDdns" : { # # -------------- Global Parameters ---------------- # # All of the global parameters have default values as shown. If these # are satisfactory you may omit them. # # "ip-address" : "127.0.0.1", # "port" : 53001, # "dns-server-timeout" : 100, # "ncr-protocol" : "UDP" # "ncr-format" : "JSON" # # ----------------- Forward DDNS ------------------ # "forward-ddns" : { "ddns-domains" : [ { "name" : "", # "key-name" : "", "dns-servers" : [ { "ip-address" : "" # ,"port" : 53 } # , # { # next DNS server for this DdnsDomain # } # : ] } # , # { # next Forward DdnsDomain # } # : ] }, # # ----------------- Reverse DDNS ------------------ # "reverse-ddns" : { "ddns-domains" : [ { "name" : "", # "key-name" : "", "dns-servers" : [ { "ip-address" : "" # ,"port" : 53 } # , # { # next DNS server for this DdnsDomain # } # : ] } # , # { # next Reverse DdnsDomain # } # : ] }, # # ------------------ TSIG keys --------------------- # "tsig-keys" : [ { "name" : "", "algorithm" : "", # Valid values for algorithm are: HMAC-MD5, HMAC-SHA1, # HMAC-SHA224, HMAC-SHA256, # HMAC-SHA384, HMAC-SHA512 # "digest-bits" : 256, # Minimum truncated length in bits. # Default 0 (means truncation is forbidden). "secret" : "" } # , # { # next TSIG Key # } ] } # If in a file by itself, it must end with an right-curly-bracket. } kea-1.1.0/doc/examples/kea6/0000775000175000017500000000000012772742653012504 500000000000000kea-1.1.0/doc/examples/kea6/mysql-reservations.json0000664000175000017500000000612512772445242017204 00000000000000# This is an example configuration file for the DHCPv6 server in Kea. # It contains configuration of the MySQL host database backend, used # to retrieve reserved addresses, host names, DHCPv4 message fields # and DHCP options from MySQL database. { "Dhcp6": { # Kea is told to listen on ethX interface only. "interfaces-config": { "interfaces": [ "ethX" ] }, # We need to specify the the database used to store leases. As of # September 2016, four database backends are supported: MySQL, # PostgreSQL, Cassandra, and the in-memory database, Memfile. # We'll use memfile because it doesn't require any prior set up. "lease-database": { "type": "memfile" }, # This is pretty basic stuff, it has nothing to do with reservations. "preferred-lifetime": 3000, "valid-lifetime": 4000, "renew-timer": 1000, "rebind-timer": 2000, # Kea supports two types of identifiers in DHCPv6: hw-address (hardware/MAC address # of the client) and duid (DUID inserted by the client). When told to do so, Kea can # check for each of these identifier types, but it takes a costly database lookup # to do so. It is therefore useful from a performance perspective to use only # the reservation types that are actually used in a given network. "host-reservation-identifiers": [ "duid", "hw-address" ], # Specify connection to the database holding host reservations. The type # specifies that the MySQL database is used. user and password are the # credentials used to connect to the database. host and name specify # location of the host where the database instance is running, and the # name of the database to use. The server processing a packet will first # check if there are any reservations specified for this client in the # reservations list, within the subnet (configuration file). If there are # no reservations there, the server will try to retrieve reservations # from this database. "hosts-database": { "type": "mysql", "name": "kea", "user": "kea", "password": "kea", "host": "localhost" }, # Define a subnet with a pool of dynamic addresses and a pool of dynamic # prefixes. Addresses and prefixes from those pools will be assigned to # clients which don't have reservations in the database. Subnet identifier # is equal to 1. If this subnet is selected for the client, this subnet # id will be used to search for the reservations within the database. "subnet6": [ { "subnet": "2001:db8:1::/48", "pools": [ { "pool": "2001:db8:1::/80" } ], "pd-pools": [ { "prefix": "2001:db8:1:8000::", "prefix-len": 56, "delegated-len": 64 } ], "interface": "ethX", "id": 1 } ] }, # The following configures logging. It assumes that messages with at least # informational level (info, warn, error and fatal) should be logged to stdout. "Logging": { "loggers": [ { "name": "kea-dhcp6", "output_options": [ { "output": "stdout" } ], "debuglevel": 0, "severity": "INFO" } ] } } kea-1.1.0/doc/examples/kea6/duid.json0000664000175000017500000000511712772445242014242 00000000000000# This is an example configuration file for DHCPv6 server in Kea. # It demonstrates how to configure Kea to use DUID-LLT with some # values specified explicitly. { "Dhcp6": { # Configure server identifier (DUID-LLT). The hexadecimal value of the # identifier will be used as link layer address component of the DUID. # The link layer type will be ethernet. The value of time is set to 0 # which indicates that the server must generate this value, i.e. use # current time. Note that it is easy to move from this configuration # to DUID-EN or DUID-LL. It would require changing the "type" value # to "EN" or "LL" respectively. The "identifier" would hold a # DUID-EN variable length identifier or DUID-LL link layer address. # The values of "time" and "htype" would be ignored for DUID-EN. # If one wanted to use a non-default enterprise-id for DUID-EN, the # "enterprise-id" parameter would need to be added. Note that only # a "type" parameter is mandatory while specifying "server-id" map. "server-id": { "type": "LLT", "identifier": "12C4D5AF870C", "time": 0, "htype": 1 }, # Kea is told to listen on ethX interface only. "interfaces-config": { "interfaces": [ "ethX" ] }, # We need to specify the the database used to store leases. As of # September 2016, four database backends are supported: MySQL, # PostgreSQL, Cassandra, and the in-memory database, Memfile. # We'll use memfile because it doesn't require any prior set up. "lease-database": { "type": "memfile" }, # Addresses will be assigned with preferred and valid lifetimes # being 3000 and 4000, respectively. Client is told to start # renewing after 1000 seconds. If the server does not respond # after 2000 seconds since the lease was granted, client is supposed # to start REBIND procedure (emergency renewal that allows switching # to a different server). "preferred-lifetime": 3000, "valid-lifetime": 4000, "renew-timer": 1000, "rebind-timer": 2000, # The following list defines subnets. Each subnet consists of at # least subnet and pool entries. "subnet6": [ { "pools": [ { "pool": "2001:db8:1::/80" } ], "subnet": "2001:db8:1::/64", "interface": "ethX" } ] }, # The following configures logging. It assumes that messages with at least # informational level (info, warn, error) will will be logged to stdout. "Logging": { "loggers": [ { "name": "kea-dhcp6", "output_options": [ { "output": "stdout" } ], "debuglevel": 0, "severity": "INFO" } ] } } kea-1.1.0/doc/examples/kea6/simple.json0000664000175000017500000000336212772445242014606 00000000000000# This is an example configuration file for DHCPv6 server in Kea. # It's a basic scenario with one IPv6 subnet configured. It is # assumed that one subnet (2001:db8:1::/64 is available directly # over ethX interface. { "Dhcp6": { # Kea is told to listen on ethX interface only. "interfaces-config": { "interfaces": [ "ethX" ] }, # We need to specify the the database used to store leases. As of # September 2016, four database backends are supported: MySQL, # PostgreSQL, Cassandra, and the in-memory database, Memfile. # We'll use memfile because it doesn't require any prior set up. "lease-database": { "type": "memfile" }, # Addresses will be assigned with preferred and valid lifetimes # being 3000 and 4000, respectively. Client is told to start # renewing after 1000 seconds. If the server does not respond # after 2000 seconds since the lease was granted, client is supposed # to start REBIND procedure (emergency renewal that allows switching # to a different server). "preferred-lifetime": 3000, "valid-lifetime": 4000, "renew-timer": 1000, "rebind-timer": 2000, # The following list defines subnets. Each subnet consists of at # least subnet and pool entries. "subnet6": [ { "pools": [ { "pool": "2001:db8:1::/80" } ], "subnet": "2001:db8:1::/64", "interface": "ethX" } ] }, # The following configures logging. It assumes that messages with at least # informational level (info, warn, error and fatal) should be logged to stdout. "Logging": { "loggers": [ { "name": "kea-dhcp6", "output_options": [ { "output": "stdout" } ], "debuglevel": 0, "severity": "INFO" } ] } } kea-1.1.0/doc/examples/kea6/pgsql-reservations.json0000664000175000017500000000615112772445242017164 00000000000000# This is an example configuration file for the DHCPv6 server in Kea. # It contains configuration of the PostgreSQL host database backend, used # to retrieve reserved addresses, host names, DHCPv4 message fields # and DHCP options from PostgreSQL database. { "Dhcp6": { # Kea is told to listen on ethX interface only. "interfaces-config": { "interfaces": [ "ethX" ] }, # We need to specify the the database used to store leases. As of # September 2016, four database backends are supported: MySQL, # PostgreSQL, Cassandra, and the in-memory database, Memfile. # We'll use memfile because it doesn't require any prior set up. "lease-database": { "type": "memfile" }, # This is pretty basic stuff, it has nothing to do with reservations. "preferred-lifetime": 3000, "valid-lifetime": 4000, "renew-timer": 1000, "rebind-timer": 2000, # Kea supports two types of identifiers in DHCPv6: hw-address (hardware/MAC address # of the client) and duid (DUID inserted by the client). When told to do so, Kea can # check for each of these identifier types, but it takes a costly database lookup # to do so. It is therefore useful from a performance perspective to use only # the reservation types that are actually used in a given network. "host-reservation-identifiers": [ "duid", "hw-address" ], # Specify connection to the database holding host reservations. The type # specifies that the PostgreSQL database is used. user and password are the # credentials used to connect to the database. host and name specify # location of the host where the database instance is running, and the # name of the database to use. The server processing a packet will first # check if there are any reservations specified for this client in the # reservations list, within the subnet (configuration file). If there are # no reservations there, the server will try to retrieve reservations # from this database. "hosts-database": { "type": "postgresql", "name": "kea", "user": "kea", "password": "kea", "host": "localhost" }, # Define a subnet with a pool of dynamic addresses and a pool of dynamic # prefixes. Addresses and prefixes from those pools will be assigned to # clients which don't have reservations in the database. Subnet identifier # is equal to 1. If this subnet is selected for the client, this subnet # id will be used to search for the reservations within the database. "subnet6": [ { "subnet": "2001:db8:1::/48", "pools": [ { "pool": "2001:db8:1::/80" } ], "pd-pools": [ { "prefix": "2001:db8:1:8000::", "prefix-len": 56, "delegated-len": 64 } ], "interface": "ethX", "id": 1 } ] }, # The following configures logging. It assumes that messages with at least # informational level (info, warn, error and fatal) should be logged to stdout. "Logging": { "loggers": [ { "name": "kea-dhcp6", "output_options": [ { "output": "stdout" } ], "debuglevel": 0, "severity": "INFO" } ] } } kea-1.1.0/doc/examples/kea6/stateless.json0000664000175000017500000000143212772017075015317 00000000000000# A very simply stateless configuration that provides information about DNS # servers to all clients, regardless of their point of attachment. # # It is also possible to specify options on a per subnet basis # in the same way as in stateful mode. # { "Dhcp6": { "interfaces-config": { "interfaces": [ "ethX" ] }, # This is the list of options that will be granted to all clients that ask. "option-data": [ { "name": "dns-servers", "data": "2001:db8::1, 2001:db8::2" } ], # Kea 0.9.1 requires lease-database to be specified, even it is not used. # In stateless mode, only options are granted, not addresses or prefixes, so # there will be no leases (unless stateless and stateful mode is used together). "lease-database": { "type": "memfile" } } } kea-1.1.0/doc/examples/kea6/several-subnets.json0000664000175000017500000000367612772445242016447 00000000000000# This is an example configuration file for DHCPv6 server in Kea. # It's a basic scenario with four IPv6 subnets configured. In each # subnet, there's a smaller pool of dynamic addresses. { "Dhcp6": { # Kea is told to listen on ethX interface only. "interfaces-config": { "interfaces": [ "ethX" ] }, # We need to specify the the database used to store leases. As of # September 2016, four database backends are supported: MySQL, # PostgreSQL, Cassandra, and the in-memory database, Memfile. # We'll use memfile because it doesn't require any prior set up. "lease-database": { "type": "memfile" }, # Addresses will be assigned with preferred and valid lifetimes # being 3000 and 4000, respectively. Client is told to start # renewing after 1000 seconds. If the server does not respond # after 2000 seconds since the lease was granted, client is supposed # to start REBIND procedure (emergency renewal that allows switching # to a different server). "preferred-lifetime": 3000, "valid-lifetime": 4000, "renew-timer": 1000, "rebind-timer": 2000, # The following list defines subnets. Each subnet consists of at # least subnet and pool entries. "subnet6": [ { "pools": [ { "pool": "2001:db8:1::/80" } ], "subnet": "2001:db8:1::/64" }, { "pools": [ { "pool": "2001:db8:2::/80" } ], "subnet": "2001:db8:2::/64" }, { "pools": [ { "pool": "2001:db8:3::/80" } ], "subnet": "2001:db8:3::/64" }, { "pools": [ { "pool": "2001:db8:4::/80" } ], "subnet": "2001:db8:4::/64" } ] }, # The following configures logging. It assumes that messages with at least # informational level (info, warn, error and fatal) should be logged to stdout. "Logging": { "loggers": [ { "name": "kea-dhcp6", "output_options": [ { "output": "stdout" } ], "debuglevel": 0, "severity": "INFO" } ] } } kea-1.1.0/doc/examples/kea6/backends.json0000664000175000017500000000747712772445242015102 00000000000000# This is an example configuration file for the DHCPv6 server in Kea. # It is a basic scenario with one IPv6 subnet configured. It demnstrates # how to configure Kea to use various backends to store leases: # - memfile # - MySQL # - PostgreSQL # - CQL (Cassandra) backend { "Dhcp6": { # Kea is told to listen on ethX interface only. "interfaces-config": { "interfaces": [ "ethX" ] }, # We need to specify lease type. Exactly one lease-database section # should be present. Make sure you uncomment only one. # 1. memfile backend. Leases information will be stored in flat CSV file. # This is the easiest backend to use as it does not require any extra # dependencies or services running. "lease-database": { "type": "memfile" }, # 2. MySQL backend. Leases will be stored in MySQL database. Make sure it # is up, running and properly initialized. See kea-admin documentation # for details on how to intialize the database. The only strictly required # parameters are type and name. If other parameters are not specified, # Kea will assume the database is avaiable on localhost, that user and # password is not necessary to connect and that timeout is 5 seconds. # Kea must be compiled with --with-dhcp-mysql option to use this backend. # "lease-database": { # "type": "mysql", # "name": "keatest", # "host": "localhost", # "user": "keatest", # "password": "secret1", # "connect-timeout": 3 # }, # 3. PostgreSQL backend. Leases will be stored in PostgreSQL database. Make # sure it is up, running and properly initialized. See kea-admin documentation # for details on how to intialize the database. The only strictly required # parameters are type and name. If other parameters are not specified, # Kea will assume the database is avaiable on localhost, that user and # password is not necessary to connect and that timeout is 5 seconds. # Kea must be compiled with --with-dhcp-pgsql option to use this backend. # "lease-database": { # "type": "pgsql", # "name": "keatest", # "host": "localhost", # "user": "keatest", # "password": "secret1" # }, # 4. CQL (Cassandra) backend. Leases will be stored in Cassandra database. Make # sure it is up, running and properly initialized. See kea-admin documentation # for details on how to intialize the database. The only strictly required # parameters are type, keyspace and contact_points. At least one contact point # must be specified, but more than one is required for redundancy. Make sure # you specify the contact points without spaces. Kea must be compiled with # --with-cql option to use this backend. # "lease-database": { # "type": "cql", # "keyspace": "keatest", # "contact_points": "192.0.2.1,192.0.2.2,192.0.2.3" # }, # Addresses will be assigned with preferred and valid lifetimes # being 3000 and 4000, respectively. Client is told to start # renewing after 1000 seconds. If the server does not respond # after 2000 seconds since the lease was granted, client is supposed # to start REBIND procedure (emergency renewal that allows switching # to a different server). "preferred-lifetime": 3000, "valid-lifetime": 4000, "renew-timer": 1000, "rebind-timer": 2000, # The following list defines subnets. Each subnet consists of at # least subnet and pool entries. "subnet6": [ { "pools": [ { "pool": "2001:db8:1::/80" } ], "subnet": "2001:db8:1::/64", "interface": "ethX" } ] }, # The following configures logging. It assumes that messages with at least # informational level (info, warn, error and fatal) should be logged to stdout. "Logging": { "loggers": [ { "name": "kea-dhcp6", "output_options": [ { "output": "stdout" } ], "debuglevel": 0, "severity": "INFO" } ] } } kea-1.1.0/doc/examples/kea6/advanced.json0000664000175000017500000000700612772445242015061 00000000000000# This is an example configuration file for DHCPv6 server in Kea. # It attempts to showcase some of the more advanced features. # Topology wise, it's a basic scenario with one IPv6 subnet configured. # It is assumed that one subnet (2001:db8:1::/64) is available directly # over ethX interface. # # The following features are currently showcased here: # 1. Configuration of MAC/hardware address sources in DHCPv6 { "Dhcp6": { # Kea is told to listen on ethX network interface only. "interfaces-config": { "interfaces": [ "ethX" ] }, # We need to specify the the database used to store leases. As of # September 2016, four database backends are supported: MySQL, # PostgreSQL, Cassandra, and the in-memory database, Memfile. # We'll use memfile because it doesn't require any prior set up. "lease-database": { "type": "memfile" }, # Kea 0.9.1 introduced MAC/hardware addresses support in DHCPv6. There is # no single reliable method of getting MAC address information in DHCPv6. # Kea supports several methods. Depending on your network set up, some # methods may be more preferable than others, hence the configuration # parameter. 'mac-sources' is a list of methods. Allowed parameters are: # any, raw, duid, ipv6-link-local, client-link-addr-option, rfc6939 (which # is an alias for client-link-addr-option), remote-id, rfc4649 (which is an # alias for remote-id, subscriber-id, rfc4580 (which is an alias for # subscriber-id) and docsis. # # Note that the order matters. Methods are attempted one by one in the order # specified until hardware address is obtained. If you don't care which method # is used, using 'any' is marginally faster than enumerating them all. # # If mac-sources are not specified, a default value of 'any' is used. "mac-sources": [ "client-link-addr-option", "duid", "ipv6-link-local" ], # RFC6422 defines a mechanism called relay-supplied options option. The relay # agent may insert certain options that the server will echo back to the # client, if certain criteria are met. One condition is that the option must # be RSOO-enabled (i.e. allowed to be echoed back). IANA maintains a list # of those options here: # http://www.iana.org/assignments/dhcpv6-parameters/dhcpv6-parameters.xhtml#options-relay-supplied # However, it is possible to allow the server to echo back additional options. # This entry marks options 110, 120 and 130 as RSOO-enabled. "relay-supplied-options": [ "110", "120", "130" ], # Addresses will be assigned with preferred and valid lifetimes # being 3000 and 4000, respectively. Client is told to start # renewing after 1000 seconds. If the server does not respond # after 2000 seconds since the lease was granted, client is supposed # to start REBIND procedure (emergency renewal that allows switching # to a different server). "preferred-lifetime": 3000, "valid-lifetime": 4000, "renew-timer": 1000, "rebind-timer": 2000, # The following list defines subnets. Each subnet consists of at # least subnet and pool entries. "subnet6": [ { "pools": [ { "pool": "2001:db8:1::/80" } ], "subnet": "2001:db8:1::/64", "interface": "ethX" } ] }, # The following configures logging. It assumes that messages with at least # informational level (info, warn, error and fatal) should be logged to stdout. "Logging": { "loggers": [ { "name": "kea-dhcp6", "output_options": [ { "output": "stdout" } ], "debuglevel": 0, "severity": "INFO" } ] } } kea-1.1.0/doc/examples/kea6/classify.json0000664000175000017500000000473212772445242015134 00000000000000# This is an example configuration file for the DHCPv4 server in Kea. # The purpose of this example is to showcase how clients can be classified. { "Dhcp6": { # Kea is told to listen on ethX interface only. "interfaces-config": { "interfaces": [ "ethX" ] }, # Let's use the simplest backend: memfile and use some reasonable values # for timers. They are of no concern for the classification demonstration. "lease-database": { "type": "memfile" }, "renew-timer": 1000, "rebind-timer": 2000, "preferred-lifetime": 3000, "valid-lifetime": 4000, # This list defines several classes that incoming packets can be assigned to. # One packet can belong to zero or more classes. "client-classes": [ # The first class attempts to match all packets coming in on ethX interface. { "name": "lab", "test": "pkt.iface == 'ethX'", "option-data": [{ "name": "dns-servers", "data": "2001:db8::1" }] }, # Let's classify all incoming RENEW (message type 5) to a separate # class. { "name": "renews", "test": "pkt6.msgtype == 5" }, # Let's pick cable modems. In this simple example we'll assume the device # is a cable modem if it sends a vendor option with enterprise-id equal # to 4491. { "name": "cable-modems", "test": "vendor.enterprise == 4491" }, ], # The following list defines subnets. Each subnet consists of at # least subnet and pool entries. "subnet6": [ { "pools": [ { "pool": "2001:db8:1::/80" } ], "subnet": "2001:db8:1::/64", "client-class": "cable-modems", "interface": "ethX" }, # The following subnet contains a class reservation for a client using # DUID 01:02:03:04:05:0A:0B:0C:0D:0E. This client will always be assigned # to this class. { "pools": [ { "pool": "2001:db8:2::/80" } ], "subnet": "2001:db8:2::/64", "reservations": [ { "duid": "01:02:03:04:05:0A:0B:0C:0D:0E", "client-classes": [ "cable-modems" ] } ], "interface": "ethX" } ] }, # The following configures logging. It assumes that messages with at least # informational level (info, warn, error and fatal) should be logged to stdout. "Logging": { "loggers": [ { "name": "kea-dhcp6", "output_options": [ { "output": "stdout" } ], "debuglevel": 0, "severity": "INFO" } ] } } kea-1.1.0/doc/examples/kea6/leases-expiration.json0000664000175000017500000000501312772445242016744 00000000000000# This is an example configuration file for DHCPv6 server in Kea. # It provides parameters controlling processing of expired leases, # a.k.a. leases reclamation. { "Dhcp6": { # Kea is told to listen on ethX interface only. "interfaces-config": { "interfaces": [ "ethX" ] }, # We need to specify the the database used to store leases. As of # September 2016, four database backends are supported: MySQL, # PostgreSQL, Cassandra, and the in-memory database, Memfile. # We'll use memfile because it doesn't require any prior set up. "lease-database": { "type": "memfile" }, # The following parameters control processing expired leases. Expired leases # will be reclaimed periodically according to the "reclaim-timer-wait-time" # parameter. Reclaimed leases will be held in the database for 1800s to # facilitate lease affinity. After this period the leases will be removed. # The frequency of removal is controlled by the "flush-reclaimed-timer-wait-time" # parameter. The lease reclamation routine will process at most 500 leases # or will last for at most 100ms, during a single run. If there are still # some unreclaimed leases after 10 attempts, a warning message is issued. "expired-leases-processing": { "reclaim-timer-wait-time": 5, "hold-reclaimed-time": 1800, "flush-reclaimed-timer-wait-time": 10, "max-reclaim-leases": 500, "max-reclaim-time": 100, "unwarned-reclaim-cycles": 10 }, # Addresses will be assigned with preferred and valid lifetimes # being 3000 and 4000, respectively. Client is told to start # renewing after 1000 seconds. If the server does not respond # after 2000 seconds since the lease was granted, client is supposed # to start REBIND procedure (emergency renewal that allows switching # to a different server). "preferred-lifetime": 3000, "valid-lifetime": 4000, "renew-timer": 1000, "rebind-timer": 2000, # The following list defines subnets. Each subnet consists of at # least subnet and pool entries. "subnet6": [ { "pools": [ { "pool": "2001:db8:1::/80" } ], "subnet": "2001:db8:1::/64", "interface": "ethX" } ] }, # The following configures logging. It assumes that messages with at least # informational level (info, warn, error and fatal) should be logged to stdout. "Logging": { "loggers": [ { "name": "kea-dhcp6", "output_options": [ { "output": "stdout" } ], "debuglevel": 0, "severity": "INFO" } ] } } kea-1.1.0/doc/examples/kea6/multiple-options.json0000664000175000017500000000374012772445242016641 00000000000000# This is an example configuration file for DHCPv6 server in Kea. # It demonstrates simple configuration of the options for a subnet. { "Dhcp6": { # Kea is told to listen on ethX interface only. "interfaces-config": { "interfaces": [ "ethX" ] }, # We need to specify the the database used to store leases. As of # September 2016, four database backends are supported: MySQL, # PostgreSQL, Cassandra, and the in-memory database, Memfile. # We'll use memfile because it doesn't require any prior set up. "lease-database": { "type": "memfile" }, # Addresses will be assigned with preferred and valid lifetimes # being 3000 and 4000, respectively. Client is told to start # renewing after 1000 seconds. If the server does not respond # after 2000 seconds since the lease was granted, client is supposed # to start REBIND procedure (emergency renewal that allows switching # to a different server). "preferred-lifetime": 3000, "valid-lifetime": 4000, "renew-timer": 1000, "rebind-timer": 2000, # Defining a subnet. There are 2 DHCP options returned to the # clients connected to this subnet. The first option is identified # by the name. The second option is identified by the code. "subnet6": [ { "pools": [ { "pool": "2001:db8:1::/80" } ], "subnet": "2001:db8:1::/64", "interface": "ethX", "option-data": [ { "name": "dns-servers", "data": "2001:db8:2::45, 2001:db8:2::100" }, { "code": 12, "data": "2001:db8:1:0:ff00::1" }, ] } ] }, # The following configures logging. It assumes that messages with at least # informational level (info, warn, error and fatal) should be logged to stdout. "Logging": { "loggers": [ { "name": "kea-dhcp6", "output_options": [ { "output": "stdout" } ], "debuglevel": 0, "severity": "INFO" } ] } } kea-1.1.0/doc/examples/kea6/hooks.json0000664000175000017500000000227112772017075014435 00000000000000# This is an example configuration file for the DHCPv6 server in Kea # illustrating the configuration of hooks libraries. It uses a basic scenario # of one IPv6 subnet configured with the default values for all parameters. {"Dhcp6": { # Kea is told to listen on the ethX interface only. "interfaces-config": { "interfaces": [ "ethX" ] }, # Set up the storage for leases. "lease-database": { "type": "memfile" }, # Set values to mandatory timers "renew-timer": 900, "rebind-timer": 1200, "preferred-lifetime": 1800, "valid-lifetime": 2700, # Define a single subnet. "subnet6": [ { "pools": [ { "pool": "2001:db8:1::/80" } ], "subnet": "2001:db8:1::/64", "interface": "ethX" } ], # Set up the hooks libraries. For this example, we assume that two libraries # are loaded, called "security" and "charging". Note that order is important: # "security" is specified first so if both libraries supply a hook function # for a given hook, the function in "security" will be called before that in # "charging". "hooks-libraries": [ { "library": "/opt/lib/security.so" }, { "library": "/opt/lib/charging.so" } ] } } kea-1.1.0/doc/examples/kea6/reservations.json0000664000175000017500000001107512772445242016041 00000000000000# This is an example configuration file for DHCPv6 server in Kea # that showcases how to do host reservations. It is # assumed that one subnet (2001:db8:1::/64) is available directly # over ethX interface. A number of hosts have various combinations # of addresses and prefixes reserved for them. { "Dhcp6": { # Kea is told to listen on ethX interface only. "interfaces-config": { "interfaces": [ "ethX" ] }, # We need to specify the the database used to store leases. As of # September 2016, four database backends are supported: MySQL, # PostgreSQL, Cassandra, and the in-memory database, Memfile. # We'll use memfile because it doesn't require any prior set up. "lease-database": { "type": "memfile" }, # This is pretty basic stuff, it has nothing to do with reservations. "preferred-lifetime": 3000, "valid-lifetime": 4000, "renew-timer": 1000, "rebind-timer": 2000, # Kea supports two types of identifiers in DHCPv6: hw-address (hardware/MAC address # of the client) and duid (DUID inserted by the client). When told to do so, Kea can # check for each of these identifier types, but it takes a costly database lookup # to do so. It is therefore useful from a performance perspective to use only # the reservation types that are actually used in a given network. "host-reservation-identifiers": [ "duid", "hw-address" ], # The following list defines subnets. Subnet, pools and interface definitions # are the same as in the regular scenario, without host reservations. # least subnet and pool entries. "subnet6": [ { "subnet": "2001:db8:1::/48", "pools": [ { "pool": "2001:db8:1::/80" } ], "pd-pools": [ { "prefix": "2001:db8:1:8000::", "prefix-len": 56, "delegated-len": 64 } ], "interface": "ethX", # Host reservations. Define several reservations, note that # they are all within the range of the pool of the dynamically # allocated address. The server will exclude the addresses from this # pool and only assign them to the client which has a reservation for # them. "reservations": [ # This is a simple host reservation. The host with DUID matching # the specified value will get an address of 2001:db8:1::100. { "duid": "01:02:03:04:05:0A:0B:0C:0D:0E", "ip-addresses": [ "2001:db8:1::100" ] }, # This is similar to the previous one, but this time the reservation is done # based on hardware/MAC address. The server will do its best to extract # the hardware/MAC address from received packets (see 'mac-sources' directive # for details). This particular reservation also specifies two extra options # to be available for this client. If there are options with the same code # specified in a global, subnet or class scope, the values defined at host level # take precedence. { "hw-address": "00:01:02:03:04:05", "ip-addresses": [ "2001:db8:1::101" ], "option-data": [ { "name": "dns-servers", "data": "3000:1::234" }, { "name": "nis-servers", "data": "3000:1::234" }] }, # This is a bit more advanced reservation. The client with the specified # DUID will get a reserved address, a reserved prefix and a hostname. # This reservation is for an address that it not within the dynamic pool. # Finally, this reservation features vendor specific options for CableLabs, # which happen to use enterprise-id 4491. Those particular values will # be returned only to the client that has a DUID matching this reservation. { "duid": "01:02:03:04:05:06:07:08:09:0A", "ip-addresses": [ "2001:db8:1:cafe::1" ], "prefixes": [ "2001:db8:2:abcd::/64" ], "hostname": "foo.example.com", "option-data": [ { "name": "vendor-opts", "data": "4491" }, { "name": "tftp-servers", "space": "vendor-4491", "data": "3000:1::234" } ] } ] } ] }, # The following configures logging. It assumes that messages with at least # informational level (info, warn, error and fatal) should be logged to stdout. "Logging": { "loggers": [ { "name": "kea-dhcp6", "output_options": [ { "output": "stdout" } ], "debuglevel": 0, "severity": "INFO" } ] } } kea-1.1.0/doc/examples/kea4/0000775000175000017500000000000012772742653012502 500000000000000kea-1.1.0/doc/examples/kea4/mysql-reservations.json0000664000175000017500000000670412772445242017205 00000000000000# This is an example configuration file for the DHCPv4 server in Kea. # It contains configuration of the MySQL host database backend, used # to retrieve reserved addresses, host names, DHCPv4 message fields # and DHCP options from MySQL database. { "Dhcp4": { # Kea is told to listen on ethX interface only. "interfaces-config": { "interfaces": [ "ethX" ] }, # We need to specify the the database used to store leases. As of # September 2016, four database backends are supported: MySQL, # PostgreSQL, Cassandra, and the in-memory database, Memfile. # We'll use memfile because it doesn't require any prior set up. "lease-database": { "type": "memfile" }, # Addresses will be assigned with a lifetime of 4000 seconds. "valid-lifetime": 4000, # Renew and rebind timers are commented out. This implies that options # 58 and 59 will not be sent to the client. In this case it is up to # the client to pick the timer values according to RFC2131. Uncomment the # timers to send these options to the client. # "renew-timer": 1000, # "rebind-timer": 2000, # Kea supports reservations by several different types of identifiers: # hw-address (hardware/MAC address of the client), duid (DUID inserted by the # client), client-id (client identifier inserted by the client) and circuit-id # (circuit identifier inserted by the relay agent). When told to do so, Kea can # check for all of those identifier types, but it takes a costly database lookup # to do so. It is therefore useful from a performance perspective to use only # the reservation types that are actually used in a given network. # The example below is not optimal from a performance perspective, but it # nicely showcases the host reservation capabilities. Please use the minimum # set of identifier types used in your network. "host-reservation-identifiers": [ "circuit-id", "hw-address", "duid", "client-id" ], # Specify connection to the database holding host reservations. The type # specifies that the MySQL database is used. user and password are the # credentials used to connect to the database. host and name specify # location of the host where the database instance is running, and the # name of the database to use. The server processing a packet will first # check if there are any reservations specified for this client in the # reservations list, within the subnet (configuration file). If there are # no reservations there, the server will try to retrieve reservations # from this database. "hosts-database": { "type": "mysql", "name": "kea", "user": "kea", "password": "kea", "host": "localhost" }, # Define a subnet with a single pool of dynamic addresses. Addresses from # this pool will be assigned to clients which don't have reservations in the # database. Subnet identifier is equal to 1. If this subnet is selected for # the client, this subnet id will be used to search for the reservations # within the database. "subnet4": [ { "pools": [ { "pool": "192.0.2.10 - 192.0.2.200" } ], "subnet": "192.0.2.0/24", "interface": "ethX", "id": 1 } ] }, # The following configures logging. It assumes that messages with at least # informational level (info, warn, error and fatal) should be logged to stdout. "Logging": { "loggers": [ { "name": "kea-dhcp4", "output_options": [ { "output": "stdout" } ], "severity": "INFO" } ] } } kea-1.1.0/doc/examples/kea4/pgsql-reservations.json0000664000175000017500000000673012772445242017165 00000000000000# This is an example configuration file for the DHCPv4 server in Kea. # It contains configuration of the PostgreSQL host database backend, used # to retrieve reserved addresses, host names, DHCPv4 message fields # and DHCP options from PostgreSQL database. { "Dhcp4": { # Kea is told to listen on ethX interface only. "interfaces-config": { "interfaces": [ "ethX" ] }, # We need to specify the the database used to store leases. As of # September 2016, four database backends are supported: MySQL, # PostgreSQL, Cassandra, and the in-memory database, Memfile. # We'll use memfile because it doesn't require any prior set up. "lease-database": { "type": "memfile" }, # Addresses will be assigned with a lifetime of 4000 seconds. "valid-lifetime": 4000, # Renew and rebind timers are commented out. This implies that options # 58 and 59 will not be sent to the client. In this case it is up to # the client to pick the timer values according to RFC2131. Uncomment the # timers to send these options to the client. # "renew-timer": 1000, # "rebind-timer": 2000, # Kea supports reservations by several different types of identifiers: # hw-address (hardware/MAC address of the client), duid (DUID inserted by the # client), client-id (client identifier inserted by the client) and circuit-id # (circuit identifier inserted by the relay agent). When told to do so, Kea can # check for all of those identifier types, but it takes a costly database lookup # to do so. It is therefore useful from a performance perspective to use only # the reservation types that are actually used in a given network. # The example below is not optimal from a performance perspective, but it # nicely showcases the host reservation capabilities. Please use the minimum # set of identifier types used in your network. "host-reservation-identifiers": [ "circuit-id", "hw-address", "duid", "client-id" ], # Specify connection to the database holding host reservations. The type # specifies that the PostgreSQL database is used. user and password are the # credentials used to connect to the database. host and name specify # location of the host where the database instance is running, and the # name of the database to use. The server processing a packet will first # check if there are any reservations specified for this client in the # reservations list, within the subnet (configuration file). If there are # no reservations there, the server will try to retrieve reservations # from this database. "hosts-database": { "type": "postgresql", "name": "kea", "user": "kea", "password": "kea", "host": "localhost" }, # Define a subnet with a single pool of dynamic addresses. Addresses from # this pool will be assigned to clients which don't have reservations in the # database. Subnet identifier is equal to 1. If this subnet is selected for # the client, this subnet id will be used to search for the reservations # within the database. "subnet4": [ { "pools": [ { "pool": "192.0.2.10 - 192.0.2.200" } ], "subnet": "192.0.2.0/24", "interface": "ethX", "id": 1 } ] }, # The following configures logging. It assumes that messages with at least # informational level (info, warn, error and fatal) should be logged to stdout. "Logging": { "loggers": [ { "name": "kea-dhcp4", "output_options": [ { "output": "stdout" } ], "severity": "INFO" } ] } } kea-1.1.0/doc/examples/kea4/several-subnets.json0000664000175000017500000000343212772445242016433 00000000000000# This is an example configuration file for DHCPv4 server in Kea. # It's a basic scenario with three IPv4 subnets configured. In each # subnet, there's a smaller pool of dynamic addresses. { "Dhcp4": { # Kea is told to listen on ethX interface only. "interfaces-config": { "interfaces": [ "ethX" ] }, # We need to specify the the database used to store leases. As of # September 2016, four database backends are supported: MySQL, # PostgreSQL, Cassandra, and the in-memory database, Memfile. # We'll use memfile because it doesn't require any prior set up. "lease-database": { "type": "memfile" }, # Addresses will be assigned with a lifetime of 4000 seconds. # The client is told to start renewing after 1000 seconds. If the server # does not respond within 2000 seconds of the lease being granted, client # is supposed to start REBIND procedure (emergency renewal that allows # switching to a different server). "valid-lifetime": 4000, "renew-timer": 1000, "rebind-timer": 2000, # The following list defines subnets. Each subnet consists of at # least subnet and pool entries. "subnet4": [ { "pools": [ { "pool": "192.0.2.1 - 192.0.2.200" } ], "subnet": "192.0.2.0/24" }, { "pools": [ { "pool": "192.0.3.100 - 192.0.3.200" } ], "subnet": "192.0.3.0/24" }, { "pools": [ { "pool": "192.0.4.1 - 192.0.4.254" } ], "subnet": "192.0.4.0/24" } ] }, # The following configures logging. It assumes that messages with at least # informational level (info, warn, error and fatal) should be logged to stdout. "Logging": { "loggers": [ { "name": "kea-dhcp4", "output_options": [ { "output": "stdout" } ], "severity": "INFO" } ] } } kea-1.1.0/doc/examples/kea4/backends.json0000664000175000017500000000743212772445242015067 00000000000000# This is an example configuration file for the DHCPv4 server in Kea. # It is a basic scenario with one IPv4 subnet configured. It demnstrates # how to configure Kea to use various backends to store leases: # - memfile # - MySQL # - PostgreSQL # - CQL (Cassandra) backend { "Dhcp4": { # Kea is told to listen on ethX interface only. "interfaces-config": { "interfaces": [ "ethX" ] }, # We need to specify lease type. Exactly one lease-database section # should be present. Make sure you uncomment only one. # 1. memfile backend. Leases information will be stored in flat CSV file. # This is the easiest backend to use as it does not require any extra # dependencies or services running. # "lease-database": { # "type": "memfile" # }, # 2. MySQL backend. Leases will be stored in MySQL database. Make sure it # is up, running and properly initialized. See kea-admin documentation # for details on how to intialize the database. The only strictly required # parameters are type and name. If other parameters are not specified, # Kea will assume the database is avaiable on localhost, that user and # password is not necessary to connect and that timeout is 5 seconds. # Kea must be compiled with --with-dhcp-mysql option to use this backend. # "lease-database": { # "type": "mysql", # "name": "keatest", # "host": "localhost", # "user": "keatest", # "password": "secret1", # "connect-timeout": 3 # }, # 3. PostgreSQL backend. Leases will be stored in PostgreSQL database. Make # sure it is up, running and properly initialized. See kea-admin documentation # for details on how to intialize the database. The only strictly required # parameters are type and name. If other parameters are not specified, # Kea will assume the database is avaiable on localhost, that user and # password is not necessary to connect and that timeout is 5 seconds. # Kea must be compiled with --with-dhcp-pgsql option to use this backend. # "lease-database": { # "type": "pgsql", # "name": "keatest", # "host": "localhost", # "user": "keatest", # "password": "secret1" # }, # 4. CQL (Cassandra) backend. Leases will be stored in Cassandra database. Make # sure it is up, running and properly initialized. See kea-admin documentation # for details on how to intialize the database. The only strictly required # parameters are type, keyspace and contact_points. At least one contact point # must be specified, but more than one is required for redundancy. Make sure # you specify the contact points without spaces. Kea must be compiled with # --with-cql option to use this backend. # "lease-database": { # "type": "cql", # "keyspace": "keatest", # "contact_points": "192.0.2.1,192.0.2.2,192.0.2.3" # }, # Addresses will be assigned with a lifetime of 4000 seconds. "valid-lifetime": 4000, # Renew and rebind timers are commented out. This implies that options # 58 and 59 will not be sent to the client. In this case it is up to # the client to pick the timer values according to RFC2131. Uncomment the # timers to send these options to the client. # "renew-timer": 1000, # "rebind-timer": 2000, # The following list defines subnets. We have only one subnet # here. We tell Kea that it is directly available over local interface. "subnet4": [ { "pools": [ { "pool": "192.0.2.1 - 192.0.2.200" } ], "subnet": "192.0.2.0/24", "interface": "ethX" } ] }, # The following configures logging. It assumes that messages with at least # informational level (info, warn, error and fatal) should be logged to stdout. "Logging": { "loggers": [ { "name": "kea-dhcp4", "output_options": [ { "output": "stdout" } ], "severity": "INFO" } ] } } kea-1.1.0/doc/examples/kea4/classify.json0000664000175000017500000000650312772445242015130 00000000000000# This is an example configuration file for the DHCPv4 server in Kea. # The purpose of this example is to showcase how clients can be classified. { "Dhcp4": { # Kea is told to listen on ethX interface only. "interfaces-config": { "interfaces": [ "ethX" ] }, # Let's use the simplest backend: memfile and use some reasonable values # for timers. They are of no concern for the classification demonstration. "lease-database": { "type": "memfile" }, "renew-timer": 1000, "rebind-timer": 2000, "valid-lifetime": 4000, # This list defines several classes that incoming packets can be assigned to. # One packet can belong to zero or more classes. "client-classes": [ # The first class attempts to match the whole hardware address to a specific # value. All incoming packets with that MAC address will get a special # value of the option. If there are many hosts that require special # treatment, it is much better to use host reservations. However, doing # tricks with MAC addresses may prove useful in some cases, e.g. # by matching OUI to known values we can detect certain vendors. { "name": "special_snowflake", "test": "pkt4.mac == 0x010203040506", "option-data": [{ "name": "domain-name-servers", "data": "127.0.0.1" }] }, # Let's classify all incoming DISCOVER (message type 1) to a separate # class. { "name": "discovers", "test": "pkt4.msgtype == 1" }, # Clients are supposed to set the transaction-id field to a random value. # Clients that send it with 0 are most likely broken. Let's mark them # as such. { "name": "broken", "test": "pkt4.transid == 0" }, # Let's pick VoIP phones. Those that send their class identifiers # as Aastra, should belong to VoIP class. For a list of all options, # see www.iana.org/assignments/bootp-dhcp-parameters/ { "name": "VoIP", "test": "substring(option[60].hex,0,6) == 'Aastra'" }, ], # The following list defines subnets. For some subnets we defined # a class that is allowed in that subnet. If not specified, # everyone is allowed. When a class is specified, only packets belonging # to that class are allowed for that subnet. "subnet4": [ { # This one is for VoIP devices only. "pools": [ { "pool": "192.0.2.1 - 192.0.2.200" } ], "subnet": "192.0.2.0/24", "client-class": "VoIP", "interface": "ethX" }, # This one doesn't have any client-class specified, so everyone # is allowed in. The normal subnet selection rules still apply, # though. There is also a static class reservation for a client # using MAC address 1a:1b:1c:1d:1e:1f. This client will always # be assigned to this class. { "pools": [ { "pool": "192.0.3.1 - 192.0.3.200" } ], "subnet": "192.0.3.0/24", "reservations": [ { "hw-address": "1a:1b:1c:1d:1e:1f", "client-classes": [ "VoIP" ] } ], "interface": "ethX" } ] }, # The following configures logging. It assumes that messages with at least # informational level (info, warn, error and fatal) should be logged to stdout. "Logging": { "loggers": [ { "name": "kea-dhcp4", "output_options": [ { "output": "stdout" } ], "severity": "INFO" } ] } } kea-1.1.0/doc/examples/kea4/leases-expiration.json0000664000175000017500000000426012772445242016745 00000000000000# This is an example configuration file for the DHCPv4 server in Kea. # It provides parameters controlling processing of expired leases, # a.k.a. leases reclamation. { "Dhcp4": { # Kea is told to listen on ethX interface only. "interfaces-config": { "interfaces": [ "ethX" ] }, # We need to specify the the database used to store leases. As of # September 2016, four database backends are supported: MySQL, # PostgreSQL, Cassandra, and the in-memory database, Memfile. # We'll use memfile because it doesn't require any prior set up. "lease-database": { "type": "memfile" }, # The following parameters control processing expired leases. Expired leases # will be reclaimed periodically according to the "reclaim-timer-wait-time" # parameter. Reclaimed leases will be held in the database for 1800s to # facilitate lease affinity. After this period the leases will be removed. # The frequency of removal is controlled by the "flush-reclaimed-timer-wait-time" # parameter. The lease reclamation routine will process at most 500 leases # or will last for at most 100ms, during a single run. If there are still # some unreclaimed leases after 10 attempts, a warning message is issued. "expired-leases-processing": { "reclaim-timer-wait-time": 5, "hold-reclaimed-time": 1800, "flush-reclaimed-timer-wait-time": 10, "max-reclaim-leases": 500, "max-reclaim-time": 100, "unwarned-reclaim-cycles": 10 }, # Addresses will be assigned with a lifetime of 4000 seconds. "valid-lifetime": 4000, # The following list defines subnets. We have only one subnet # here. We tell Kea that it is directly available over local interface. "subnet4": [ { "pools": [ { "pool": "192.0.2.1 - 192.0.2.200" } ], "subnet": "192.0.2.0/24", "interface": "ethX" } ] }, # The following configures logging. It assumes that messages with at least # informational level (info, warn, error and fatal) should be logged to stdout. "Logging": { "loggers": [ { "name": "kea-dhcp4", "output_options": [ { "output": "stdout" } ], "severity": "INFO" } ] } } kea-1.1.0/doc/examples/kea4/multiple-options.json0000664000175000017500000000377412772445242016646 00000000000000# This is an example configuration file for the DHCPv4 server in Kea. # It demonstrates simple configuration of the options for a subnet. { "Dhcp4": { # Kea is told to listen on ethX interface only. "interfaces-config": { "interfaces": [ "ethX" ] }, # We need to specify the the database used to store leases. As of # September 2016, four database backends are supported: MySQL, # PostgreSQL, Cassandra, and the in-memory database, Memfile. # We'll use memfile because it doesn't require any prior set up. "lease-database": { "type": "memfile" }, # Addresses will be assigned with a lifetime of 4000 seconds. "valid-lifetime": 4000, # Renew and rebind timers are commented out. This implies that options # 58 and 59 will not be sent to the client. In this case it is up to # the client to pick the timer values according to RFC2131. Uncomment the # timers to send these options to the client. # "renew-timer": 1000, # "rebind-timer": 2000, # Defining a subnet. There are 3 DHCP options returned to the # clients connected to this subnet. The first two options are # identified by the name. The third option is identified by the # option code. "subnet4": [ { "pools": [ { "pool": "192.0.2.10 - 192.0.2.200" } ], "subnet": "192.0.2.0/24", "interface": "ethX", "option-data": [ { "name": "domain-name-servers", "data": "192.0.2.1, 192.0.2.2" }, { "name": "routers", "data": "192.0.2.1" }, { "code": 15, "data": "example.org" } ] } ] }, # The following configures logging. It assumes that messages with at least # informational level (info, warn, error and fatal) should be logged to stdout. "Logging": { "loggers": [ { "name": "kea-dhcp4", "output_options": [ { "output": "stdout" } ], "severity": "INFO" } ] } } kea-1.1.0/doc/examples/kea4/hooks.json0000664000175000017500000000212112772017075014425 00000000000000# This is an example configuration file for the DHCPv4 server in Kea # illustrating the configuration of hooks libraries. It uses a basic scenario # of one IPv4 subnet configured with the default values for all parameters. {"Dhcp4": { # Kea is told to listen on the ethX interface only. "interfaces-config": { "interfaces": [ "ethX" ] }, # Set up the storage for leases. "lease-database": { "type": "memfile" }, "valid-lifetime": 1800, # Define a single subnet. "subnet4": [ { "pools": [ { "pool": "192.0.2.1 - 192.0.2.200" } ], "subnet": "192.0.2.0/24", "interface": "ethX" } ], # Set up the hooks libraries. For this example, we assume that two libraries # are loaded, called "security" and "charging". Note that order is important: # "security" is specified first so if both libraries supply a hook function # for a given hook, the function in "security" will be called before that in # "charging". "hooks-libraries": [ { "library": "/opt/lib/security.so" }, { "library": "/opt/lib/charging.so" } ] } } kea-1.1.0/doc/examples/kea4/reservations.json0000664000175000017500000001160612772445242016037 00000000000000# This is an example configuration file for the DHCPv4 server in Kea. # It contains one subnet in which there are two static address reservations # for the clients identified by the MAC addresses. { "Dhcp4": { # Kea is told to listen on ethX interface only. "interfaces-config": { "interfaces": [ "ethX" ] }, # We need to specify the the database used to store leases. As of # September 2016, four database backends are supported: MySQL, # PostgreSQL, Cassandra, and the in-memory database, Memfile. # We'll use memfile because it doesn't require any prior set up. "lease-database": { "type": "memfile" }, # Addresses will be assigned with a lifetime of 4000 seconds. "valid-lifetime": 4000, # Renew and rebind timers are commented out. This implies that options # 58 and 59 will not be sent to the client. In this case it is up to # the client to pick the timer values according to RFC2131. Uncomment the # timers to send these options to the client. # "renew-timer": 1000, # "rebind-timer": 2000, # Kea supports reservations by several different types of identifiers: # hw-address (hardware/MAC address of the client), duid (DUID inserted by the # client), client-id (client identifier inserted by the client) and circuit-id # (circuit identifier inserted by the relay agent). When told to do so, Kea can # check for all of those identifier types, but it takes a costly database lookup # to do so. It is therefore useful from a performance perspective to use only # the reservation types that are actually used in a given network. # The example below is not optimal from a performance perspective, but it # nicely showcases the host reservation capabilities. Please use the minimum # set of identifier types used in your network. "host-reservation-identifiers": [ "circuit-id", "hw-address", "duid", "client-id" ], # Define a subnet with four reservations. Some of the reservations belong # to the dynamic pool. Kea is able to handle this case, but it is not # recommended from a performance perspective, as Kea would not only need to # check if a given address is free, but also whether it is reserved. # To avoid this check, one can change reservation-mode to out-of-pool, rather # than 'all'. If a subnet does not have reservations at all, the reservation # lookup can be skipped altogether (reservation-mode is set to 'disabled'). # Note that the second reservation is for an address which is within the # range of the pool of the dynamically allocated address. The server will # exclude this address from this pool and only assign it to the client which # has a reservation for it. "subnet4": [ { "pools": [ { "pool": "192.0.2.1 - 192.0.2.200" } ], "subnet": "192.0.2.0/24", "interface": "eth0", "reservations": [ # This is a reservation for a specific hardware/MAC address. It's a very # simple reservation: just an address and nothing else. { "hw-address": "1a:1b:1c:1d:1e:1f", "ip-address": "192.0.2.202" }, # This is a reservation for a specific client-id. It also shows # the this client will get a reserved hostname. A hostname can be defined # for any identifier type, not just client-id. { "client-id": "01:11:22:33:44:55:66", "ip-address": "192.0.2.100", "hostname": "special-snowflake" }, # The third reservation is based on DUID. This reservation also # defines special option values for this particular client. If # the domain-name-servers option would have been defined on a global, # subnet or class level, the host specific values take preference. { "duid": "01:02:03:04:05", "ip-address": "192.0.2.203", "option-data": [ { "name": "domain-name-servers", "data": "10.1.1.202,10.1.1.203" } ] }, # The fourth reservation is based on circuit-id. This is an option inserted # by the relay agent that forwards the packet from client to the server. # In this example the host is also assigned vendor specific options. { "client-id": "01:11:22:33:44:55:66", "ip-address": "192.0.2.204", "option-data": [ { "name": "vivso-suboptions", "data": "4491" }, { "name": "tftp-servers", "space": "vendor-4491", "data": "10.1.1.202,10.1.1.203" } ] } ] } ] }, # The following configures logging. It assumes that messages with at least # informational level (info, warn, error and fatal) should be logged to stdout. "Logging": { "loggers": [ { "name": "kea-dhcp4", "output_options": [ { "output": "stdout" } ], "severity": "INFO" } ] } } kea-1.1.0/doc/examples/kea4/single-subnet.json0000664000175000017500000000327012772445242016070 00000000000000# This is an example configuration file for the DHCPv4 server in Kea. # It is a basic scenario with one IPv4 subnet configured. The subnet # contains a single pool of dynamically allocated addresses. { "Dhcp4": { # Kea is told to listen on ethX interface only. "interfaces-config": { "interfaces": [ "ethX" ] }, # We need to specify the the database used to store leases. As of # September 2016, four database backends are supported: MySQL, # PostgreSQL, Cassandra, and the in-memory database, Memfile. # We'll use memfile because it doesn't require any prior set up. "lease-database": { "type": "memfile" }, # Addresses will be assigned with a lifetime of 4000 seconds. "valid-lifetime": 4000, # Renew and rebind timers are commented out. This implies that options # 58 and 59 will not be sent to the client. In this case it is up to # the client to pick the timer values according to RFC2131. Uncomment the # timers to send these options to the client. # "renew-timer": 1000, # "rebind-timer": 2000, # The following list defines subnets. We have only one subnet # here. We tell Kea that it is directly available over local interface. "subnet4": [ { "pools": [ { "pool": "192.0.2.1 - 192.0.2.200" } ], "subnet": "192.0.2.0/24", "interface": "ethX" } ] }, # The following configures logging. It assumes that messages with at least # informational level (info, warn, error and fatal) should be logged to stdout. "Logging": { "loggers": [ { "name": "kea-dhcp4", "output_options": [ { "output": "stdout" } ], "severity": "INFO" } ] } } kea-1.1.0/doc/devel/0000775000175000017500000000000012772742653011137 500000000000000kea-1.1.0/doc/devel/mainpage.dox0000664000175000017500000001047712772445242013357 00000000000000// Copyright (C) 2012-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/. /** * @mainpage Kea Developer's Guide * * Welcome to the Kea Developer's Guide. This documentation is addressed at * either existing or prospective Kea developers and contributors, and * provides information needed to extend and maintain Kea source code. * If you wish to write hook code - the code that is loaded by Kea at * run-time and modifies its behavior, you should read the section * @ref hooksdgDevelopersGuide. * * Kea maintenance information is divided into a number of sections. * Information on DHCP-specific topics can be found * in the @ref dhcpMaintenanceGuide. General topics are discussed in * @ref miscellaneousTopics. * * If you are a user or system administrator, rather than software engineer, * you should read the * Kea * Administrator Reference Manual instead. If you are using a beta or * development version of Kea, the * * development version of the manual is recommended. * * Regardless of your field of expertise, you are encouraged to visit the * Kea webpage (http://kea.isc.org) * * @section contrib Contributor's Guide * - @subpage contributorGuide - This page describes the process of sending * a patch to ISC and what happens next. Please read it if you are considering * sending us any code. * * @section buildingKeaWithUnitTests Building Kea with Unit tests * - @subpage unitTests * - @subpage unitTestsIntroduction * - @subpage unitTestsEnvironmentVariables * - @subpage unitTestsDatabaseConfig * * @section hooksFramework Hooks Framework * - @subpage hooksdgDevelopersGuide * - @subpage dhcpv4Hooks * - @subpage dhcpv6Hooks * - @subpage hooksComponentDeveloperGuide * - @subpage hooksmgMaintenanceGuide * - @subpage libdhcp_user_chk * * @section dhcpMaintenanceGuide DHCP Maintenance Guide * - @subpage dhcp4 * - @subpage dhcpv4ConfigParser * - @subpage dhcpv4ConfigInherit * - @subpage dhcpv4OptionsParse * - @subpage dhcpv4DDNSIntegration * - @subpage dhcpv4Classifier * - @subpage dhcpv4ConfigBackend * - @subpage dhcpv4SignalBasedReconfiguration * - @subpage dhcpv4Other * - @subpage dhcpv4o6Dhcp4 * - @subpage dhcp6 * - @subpage dhcpv6ConfigParser * - @subpage dhcpv6ConfigInherit * - @subpage dhcpv6DDNSIntegration * - @subpage dhcpv6OptionsParse * - @subpage dhcpv6Classifier * - @subpage dhcpv6ConfigBackend * - @subpage dhcpv6SignalBasedReconfiguration * - @subpage dhcpv6Other * - @subpage dhcpv4o6Dhcp6 * - @subpage d2 * - @subpage d2CPL * - @subpage d2ProcessDerivation * - @subpage d2ConfigMgt * - @subpage d2NCRReceipt * - @subpage d2DDNSUpdateExecution * - @subpage d2EventLoop * - @subpage d2TransDetail * - @subpage d2StateModel * - @subpage d2TransExecExample * - @subpage lfc * - @subpage lfcProcessing * - @subpage lfcFiles * - @subpage ctrlSocket * - @subpage ctrlSocketOverview * - @subpage ctrlSocketClient * - @subpage ctrlSocketImpl * - @subpage ctrlSocketConnections * - @subpage libdhcp * - @subpage libdhcpIntro * - @subpage libdhcpRelay * - @subpage libdhcpIfaceMgr * - @subpage libdhcpPktFilter * - @subpage libdhcpPktFilter6 * - @subpage libdhcpErrorLogging * - @subpage libdhcpsrv * - @subpage leasemgr * - @subpage cfgmgr * - @subpage hostmgr * - @subpage optionsConfig * - @subpage allocengine * - @subpage timerManager * - @subpage leaseReclamationRoutine * - @subpage subnetSelect * - @subpage dhcp4o6Ipc * - @subpage libdhcp_ddns * - @subpage dhcpDatabaseBackends * - @subpage dhcpEval * - @subpage configBackend * - @subpage configBackendJSONDesign * - @subpage perfdhcpInternals * * @section miscellaneousTopics Miscellaneous Topics * - @subpage logKeaLogging * - @subpage logBasicIdeas * - @subpage logDeveloperUse * - @subpage logNotes * - @subpage LoggingApi * - @subpage SocketSessionUtility * - Documentation warnings and errors * */ kea-1.1.0/doc/devel/config-backend.dox0000664000175000017500000001374512772445242014431 00000000000000// Copyright (C) 2014-2015 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/. /** @page configBackend Kea Configuration Backends @section configBackendIntro Introduction Kea started as a sub-project in BIND10 that used a program (called bindctl) to deliver configuration information to its modules. This potentially allowed for modules to get their configuration information in a variaty of ways using what were known as configuration backends. After BIND10 was cancelled, the Kea project briefly tried to maintain backward compatibility with the BIND10 framework, but the effort was discontinued due to lack of interest. Currently the Kea team does not plan to develop any additional configuration backends. Instead, effort is being focused on enhancing the current control channel (see @ref ctrlSocket) to be as flexible as possible. If you are thinking about developing new ways to configure Kea, the recommendation is to write an external piece of software that will communicate with Kea using this channel. @section configBackendHistoric Alternate Configuration Backends While this section currently has no practical value, it may become useful one day to develop a minimalistic, stripped down Kea version that does not have any command interface at all. This could prove useful for running Kea in embedded regime. The following steps are needed for the DHCPv4 server to be able to process a new method of configuration. (It is assumed that the modified component is DHCPv4. Similar approach applies to the other components: DHCPv6 or DHCP-DDNS): -# Write your own implementation of isc::dhcp::ControlledDhcpv4Srv::init(), isc::dhcp::ControlledDhcpv4Srv::init() and isc::dhcp::ControlledDhcpv4Srv::cleanup(), and put it in the src/bin/dhcp4 directory (e.g. as foo_controller.cc). -# Modify src/bin/dhcp4/Makefile.am to include your file (e.g. foo_controller.cc) in the build. -# Modify the AC_ARG_WITH(kea-config,...) macro in configure.ac to include an entry for your configuration backend. -# Add your own AM_CONDITIONAL(CONFIG_BACKEND_FOO, ...) and AC_DEFINE(CONFIG_BACKEND_FOO, ...) macros to configure.ac (following the above-mentioned AC_ARG_WITH macro) to set the C++ macro for your backend. -# Modify the sanity check in configure.ac to allow your configuration backend name. Optionally you can also: -# Implement unit tests for your backend in the src/bin/dhcp4/tests directory. -# Modify src/bin/dhcp4/tests/Makefile.am to include the file(s) containing the unit tests. @section configBackendJSONDesign The JSON Configuration Backend The following are some details of the JSON backend framework. -# Each backend uses the common code for configuration and command processing callbacks. They all assume that JSON formatted parameters are sent and they are expected to return well formatted JSON responses. The exact format of configuration and commands is module-specific.

-# A command handler handles the reading the configuration from a file. Its main responsibility is to load the configuration and process it. The JSON backend must call that handler when starting up the server. This is implemented in configure() in the kea_controller.cc files in src/bin/dhcp4 and src/bin/dhcp6 directories.

-# The current JSON parser in @ref isc::data::Element::fromJSON() has been extended to allow optional preprocessing. For now, that capability simply removes whole-line comments starting with the hash character, but it is expected to grow over time (in-line comments and file inclusions are the obvious envisaged additions). This is implemented in @ref isc::data::Element::fromJSONFile.

-# The current format of the BIND10 configuration file (BIND 10 stored its configuration in (installation directory) /var/bind10/b10-config.db) has been retained as the configuration file format. Its actual naming is now arbitrary and left up to the user (it is passed as a parameter to the -c command line option). From the implementation perspective, this is slight change from the BIND10 days, as back then a subset of the configuration was received by the daemon processes. Nowadays the whole configuration is passed. To take a specific example, the following is how b10-config.db looks today: @code { "Init": { ... } "Dhcp4": { "subnet4" { subnet definitions here }, "option-data" { option data here }, "interfaces": [ "eth0" ], ... }, "Dhcp6": { "subnet6" { subnet definitions here }, "option-data" { option data here }, "interfaces": [ "eth0" ], ... }, "Logging": { "Loggers": [{"name": *, "severity": "DEBUG" }] } } @endcode The Kea components used to receive only relevant parts of it (e.g. Kea4 received configuration data that only contained the content of the Dhcp4 element). Now each component receives all of it: the code iterates over the top level elements and picks the appropriate tree (or get the element by name). That approach makes the common configuration (such as the logging initialization code) very easy to share among Kea4, Kea6 and DHCP-DDNS.

-# The .spec files used in BIND 10 by the control program to validate commands have been retained. They will be kept and maintained even though no use of them is currently planned. At some future time syntax validation may be implemented, although it is out of scope for Kea 0.9 (and probably for 1.0 as well, as it is a pretty big task).

-# A shell script has been added (as src/bin/keactrl/keactrl) to start, stop and reconfigure the daemons. Its only job is to pass the configuration file to each daemon and remember its PID file, so that sending signals is possible (for configuration reload or shutdown). It is also able to print out a status. */ kea-1.1.0/doc/devel/contribute.dox0000664000175000017500000003365712772445242013761 00000000000000// Copyright (C) 2013-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/. /** @page contributorGuide Kea Contributor's Guide So you found a bug in Kea or plan to develop an extension and want to send us a patch? Great! This page will explain how to contribute your changes smoothly. @section contributorGuideWritePatch Writing a patch Before you start working on a patch or a new feature, it is a good idea to discuss it first with Kea developers. You can post your questions to the \c kea-dev mailing list (https://lists.isc.org/mailman/listinfo/kea-dev) or kea-users (https://lists.isc.org/mailman/listinfo/kea-users). The kea-users list is intended for users who are not interested in the internal workings or development details of Kea: it is OK to ask for feedback regarding new design or the best proposed solution to a certain problem, but all the internal details should be discussed on kea-dev and not posted to kea-users. The first step in writing the patch or new feature should be to get the source code from our Git repository. The procedure is very easy and is explained here: http://kea.isc.org/wiki/GitGuidelines. While it is possible to provide a patch against the latest stable release, it makes the review process much easier if it is for latest code from the Git \c master branch. OK, so you have written a patch? Great! Before you submit it, make sure that your code compiles. This may seem obvious, but there's more to it. You have surely checked that it compiles on your system, but Kea is portable software. Besides Linux, it is compiled and used on relatively uncommon systems like OpenBSD. Will your code compile and work there? What about endianess? It is likely that you used a regular x86 architecture machine to write your patch, but the software is expected to run on many other architectures. You may take a look at system specific build notes (http://kea.isc.org/wiki/Install). For a complete list of systems we build on, you may take a look at the following build farm report: https://jenkins.isc.org/view/Kea_BuildFarm/ . Does your patch conform to Kea coding guidelines (http://kea.isc.org/wiki/CodingGuidelines)? You can submit a patch that does not adhere to them, but that will reduce its chances of being accepted. If the deviations are minor, one of the Kea engineers who does the review will likely fix the issues. However, if there are lots of issues, the reviewer may simply reject the patch and ask you to fix it before re-submitting. @section contributorGuideUnittests Running unit-tests One of the ground rules in Kea development is that every piece of code has to be tested. We now have an extensive set of unit-tests for almost every line of code. Even if you are fixing something small, like a single line fix, you are encouraged to write unit-tests for that change. That is even more true for new code: if you write a new function, method or a class, you definitely should write unit-tests for it. To ensure that everything is tested, ISC uses a development method called Test Driven Development (TDD). In TDD, a feature is developed alongside the tests, with the tests being written first. In detail, a test is written for a small piece of functionality and run against the existing code. (In the case where the test is a unit test for a function, it would be run against an empty (unimplemented) function.) The test should fail. A minimal amount of code is then written, just enough to get the test to pass. Then the process is repeated for the next small piece of functionality. This continues until all the functionality has been implemented. This approach has two advantages: - By writing a test first and then only enough code to pass the test, that code is fully tested. By repeating this process until the feature is fully implemented, all the code gets test coverage. You avoid the situation where not enough tests have been written to check all the code. - By running the test before the code implementing the function is written and observing the test fail, you can detect the situation where a bug in the test code will cause it to pass regardless of the code being tested. Initially, some people unfamiliar with that approach react with "but my change is simple and I tested that it works". That approach is both insufficient and short-sighted. It is insufficient, because manual testing is by definition laborious and can't really be done on the multitude of systems we run Kea on. It is short-sighted, because even with your best intentions you will not be able to dedicate any significant amount of time for repeated testing of your improved code. The old ISC DHCP has two decades of history behind it and we hope to make Kea last similar time span. Over such long periods, code tends to be refactored several times. The change you made may be affected by some other change or by the code that hasn't been written yet. See @ref unitTests for instructions on how to run unit-tests. If you happen to touch any database related code, make sure you compile your code with @c --with-dhcp-mysql, @c --with-dhcp-pgsql and/or @c --with-cql as needed. For example, if you change something substantial, make sure the other compilation options still work. If you happen to add new files or have modified any \c Makefile.am files, it is also a good idea to check if you haven't broken the distribution process: @code make distcheck @endcode There are other useful switches which can be passed to configure. It is always a good idea to use \c --enable-logger-checks, which does sanity checks on logger parameters. Use \c --enable-debug to enable various additional consistency checks that reduce performance but help during development. If you happen to modify anything in the documentation, use \c --enable-generate-docs. If you are modifying DHCP code, you are likely to be interested in enabling a non-default database backends for DHCP. Note that if the backend is not enabled, the database-specific unit-tests are skipped. To enable the MySQL backend, use the switch \c --with-dhcp-mysql; for PostgreSQL, use \c --with-dhcp-pgsql. A complete list of all switches can be obtained with the command: @code ./configure --help @endcode @section contributorGuideSendPatch Sending the patch There are several ways how you can send your changes. They are listed here from most to least preferred. - Send pull request (PR) on github. This is by far the most convenient way for everyone. See the excellent documentation on github: https://help.github.com/articles/creating-a-pull-request/ for details. In essence, you need github account (spam/hassle free, takes one minute to set up). Then you can fork the Kea repository, commit changes to your repo and ask us to pull your changes into official Kea repository. This has a number of advantages. First, it is made against a specific code version, which can be easily checked with git log command. Second, this request pops up instantly on our list of open pull requests and will stay there. The third benefit is that the pull request mechanism is very flexible. Kea engineers (and other users, too) can comment on it, attach links, mention other users etc. You as a submitter can augment the patch by commiting extra changes to your repository. Those extra commits will appear instantly in the pull request. This is really useful during the review. Finally, ISC engineers can better assess all open pull requests and add labels to them, such as "enhancement", "bug", or "unit-tests missing". This makes our life easier. Oh, and your commits will later be shown as yours in github history. If you care for that kind of things, once the patch is merged, you'll be automatically listed as contributor and Kea will be listed as project you have contributed to. - Create a ticket in the Kea trac and attach your patch to it. Sending a patch has a number of disadvantages. First, if you don't specify the base version against which it was created, one of ISC engineers will have to guess that or go through a series of trials and errors to find that out. If the code doesn't compile, the reviewer will not know if the patch is broken or maybe it was applied to incorrect base code. Another frequent problem is that it may be possible that the patch didn't include any new files you have added. If we happen to have any comments that you as submitter are expected to address (and in the overwhelming majority of cases, we have), you will be asked to send an updated patch. It is not uncommon to see several rounds of such reviews, so this can get very complicated very quickly. Please make sure your ticket is created in the default milestone "kea-proposed". ISC engineers review new tickets once a week and assign them to specific milestones. Please do not add tickets to working milestones directly. Having a ticket in trac ensures that the patch will never be forgotten and it will show up on our trac reports. It's not required, but much appreciated if you send a short note to the kea-dev mailing list explaining what you did with the code and announce the ticket number. - Send a patch to the kea-dev list. This is the third preferred method, if you can't or don't want to use github and trac for whatever reason. If you send a patch to a mailing list in a wrong time, e.g. shortly before a release, ISC engineers may miss it or perhaps they will see it and then forget about it. Nevertheless, it is still doable and we successfully accepted patches that way. It just takes more time from everyone involved, so it's a slower process in general. - Send a tarball with your modified code. This is really the worst way one can contribute a patch. It has a number of disadvantages. In particular, someone will need to find out which version the code was based on and generate the patch. It's not a rocket science, but it may be a very mundane thing to do if the ISC engineer does not know the version in advance. The mailing list has a limit on the message size (for good reasons), so you'll likely need to upload it somewhere first. ISC engineers often don't pick up new tickets instantly, so it may have to wait weeks before the tarball is looked at. The tarball does not benefit from most of the advantages mentioned for github, like the ability to easily update the code, have a meaningful discussion or see what the exact scope of changes are. Nevertheless, if we given a choice of getting a tarball or not getting a patch at all, we prefer tarballs. Just keep in mind that processing a tarball is really cumbersome for ISC engineers, so it may take sigificantly longer than other ways. @section contributorGuideReview Going through a review Once you let us submitted a patch using one of the ways above, the action is on one of the ISC engineers. First, we will need either a trac ticket or PR on github. We prefer the original submitter fill them as he or she has the best understanding of the purpose of the change and may have any extra information, e.g. "this patch fixes compilation issue on FreeBSD 10.1". If there there is no PR and no trac ticket, we will create one. Depending on the subjective importance and urgency as perceived by the ISC engineer, the ticket or PR will be assigned to one of the milestones. Sooner or later, one of ISC engineers will do the review. Here's the tricky part. One of Kea developers will review your patch, but it may not happen immediately. Unfortunately, developers are usually working under a tight schedule, so any extra unplanned review work may take a while sometimes. Having said that, we value external contributions very much and will do whatever we can to review patches in a timely manner. Don't get discouraged if your patch is not accepted after first review. To keep the code quality high, we use the same review processes for external patches as we do for internal code. It may take some cycles of review/updated patch submissions before the code is finally accepted. The nature of the review process is that it emphasizes areas that need improvement. If you are not used to the review process, you may get the impression that the feedback is negative. It is not: even the Kea developers seldom see reviews that say "All OK please merge". Once the process is almost complete, the developer will likely ask you how you would like to be credited. The typical answers are by first and last name, by nickname, by company name or anonymously. Typically we will add a note to the \c ChangeLog and also set you as the author of the commit applying the patch and update the contributors section in the AUTHORS file. If the contributed feature is big or critical for whatever reason, it may also be mentioned in release notes. Sadly, we sometimes see patches that are submitted and then the submitter never responds to our comments or requests for an updated patch. Depending on the nature of the patch, we may either fix the outstanding issues on our own and get another ISC engineer to review them or the ticket may end up in our "Outstanding Tasks" milestone. When a new release is started, we go through the tickets in Outstanding Tasks, select a small number of them and move them to whatever the current milestone is. Keep that in mind if you plan to submit a patch and forget about it. We may accept it eventually, but it's much, much faster process if you participate in it. @section contributorGuideExtra Extra steps If you are interested in knowing the results of more in-depth testing, you are welcome to visit the ISC Jenkins page: https://jenkins.isc.org This is a live result page with all tests being run on various systems. Besides basic unit-tests, we also have reports from valgrind (memory debugger), cppcheck and clang-analyzer (static code analyzers), Lettuce system tests and more. Although it is not possible for non ISC employees to run tests on that farm, it is possible that your contributed patch will end up there sooner or later. We also have ISC Forge tests running, but currently the test results are not publicly available. */ kea-1.1.0/doc/devel/unit-tests.dox0000664000175000017500000002500012772445242013701 00000000000000// Copyright (C) 2015-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/. /** @page unitTests Building Kea with Unit Tests @section unitTestsIntroduction Introduction Kea uses the Google C++ Testing Framework (also called googletest or gtest) as a base for our C++ unit-tests. See https://github.com/google/googletest for details. We used to have Python unit-tests inherited from BIND10 days but have been removed, so please do not write any new Kea unit tests in Python. If you want to write DHCP tests in Python, we encourage you to take a look at ISC Forge: http://kea.isc.org/wiki/IscForge . You must have \c gtest installed or at least extracted in a directory before compiling Kea unit-tests. To enable unit-tests in Kea, use: @code ./configure --with-gtest=/path/to/your/gtest/dir @endcode or @code ./configure --with-gtest-source=/path/to/your/gtest/dir @endcode Depending on how you compiled or installed \c gtest (e.g. from sources or using some package management system) one of those two switches will find \c gtest. After that you make and run the unit-tests with: @code make check @endcode @section unitTestsEnvironmentVariables Environment Variables The following environment variable can affect the unit tests: - KEA_LOCKFILE_DIR - Specifies a directory where the logging system should create its lock file. If not specified, it is prefix/var/run/kea, where prefix defaults to /usr/local. This variable must not end with a slash. There is one special value, "none", which instructs Kea to not create a lock file at all. This may cause issues if several processes log to the same file. (Also see the Kea User's Guide, section 15.3.) - KEA_LOGGER_DESTINATION - Specifies the logging destination. If not set, logged messages will not be recorded anywhere. There are three special values: stdout, stderr and syslog. Any other value is interpreted as a filename. (Also see Kea User's Guide, section 15.3.) - KEA_PIDFILE_DIR - Specifies the directory which should be used for PID files as used by dhcp::Daemon or its derivatives. If not specified, the default is prefix/var/run/kea, where prefix defaults to /usr/local. This variable must not end with a slash. - KEA_SOCKET_TEST_DIR - if set, it specifies the directory where Unix sockets are created. There is an operating system limitation on how long a Unix socket path can be, typically slightly over 100 characters. If you happen to build and run unit-tests in deeply nested directories, this may become a problem. KEA_SOCKET_TEST_DIR can be specified to instruct unit-test to use a different directory. It must not end with slash. @section unitTestsDatabaseConfig Databases Configuration for Unit Tests With the use of databases requiring separate authorisation, there are certain database-specific pre-requisites for successfully running the unit tests. These are listed in the following sections. @subsection unitTestsDatabaseUsers Database Users Required for Unit Tests Unit tests validating database backends require that the keatest database is created. This database should be empty. The unit tests also require that the keatest user is created and that this user is configured to access the database with a password of keatest. Unit tests use these credentials to create database schema, run test cases and drop the schema. Thus, the keatest user must have sufficiently high privileges to create and drop tables, as well as insert and modify the data within those tables. The database backends which support read only access to the host reservations databases (currently MySQL and PostgreSQL) include unit tests verifying that a database user with read-only privileges can be used to retrieve host reservations. Those tests require another user, keatest_readonly, with SQL SELECT privilege to the keatest database (i.e. without INSERT, UPDATE etc.), is also created. keatest_readonly should also have the password keatest. The following sections provide step-by-step guidelines how to setup the databases for running unit tests. @subsection mysqlUnitTestsPrerequisites MySQL Database The steps to create the database and users are: -# Log into MySQL as root: @verbatim % mysql -u root -p Enter password: : mysql>@endverbatim\n -# Create the test database. This must be called "keatest": @verbatim mysql> CREATE DATABASE keatest; mysql>@endverbatim\n -# Create the users under which the test client will connect to the database (the apostrophes around the words keatest, keatest_readonly, and localhost are required): @verbatim mysql> CREATE USER 'keatest'@'localhost' IDENTIFIED BY 'keatest'; mysql> CREATE USER 'keatest_readonly'@'localhost' IDENTIFIED BY 'keatest'; mysql>@endverbatim\n -# Grant the created users permissions to access the keatest database (again, the apostrophes around the user names and localhost are required): @verbatim mysql> GRANT ALL ON keatest.* TO 'keatest'@'localhost'; mysql> GRANT SELECT ON keatest.* TO 'keatest_readonly'@'localhost'; mysql>@endverbatim\n -# Exit MySQL: @verbatim mysql> quit Bye %@endverbatim The unit tests are run automatically when "make check" is executed (providing that Kea has been build with the \c --with-dhcp-mysql switch (see the installation section in the Kea Administrator Reference Manual). @subsection pgsqlUnitTestsPrerequisites PostgreSQL Database PostgreSQL set up differs from system to system. Please consult your operating system-specific PostgreSQL documentation. The remainder of that section uses Ubuntu 13.10 x64 (with PostgreSQL 9.0+) as an example. On Ubuntu, PostgreSQL is installed (with sudo apt-get install postgresql) under user postgres. To create new databases or add new users, initial commands must be issued under this username: @verbatim $ sudo -u postgres psql postgres [sudo] password for thomson: psql (9.1.12) Type "help" for help. postgres=# CREATE USER keatest WITH PASSWORD 'keatest'; CREATE ROLE postgres=# CREATE DATABASE keatest; CREATE DATABASE postgres=# GRANT ALL PRIVILEGES ON DATABASE keatest TO keatest; GRANT postgres=# \q @endverbatim PostgreSQL versions earlier than 9.0 don't provide an SQL statement for granting privileges on all tables in a database. In newer PostgreSQL versions, it is possible to grant specific privileges on all tables within a schema. However, this only affects tables which exist when the privileges are granted. To ensure that the user has specific privileges to tables dynamically created by the unit tests, the default schema privileges must be altered. The following example demonstrates how to create the user keatest_readonly, which has SELECT privilege to the tables within the keatest database, in Postgres 9.0+. For earlier versions of Postgres, it is recommended to simply grant full privileges to keatest_readonly, using the same steps as for the keatest user. @verbatim $ psql -U postgres Password for user postgres: psql (9.1.12) Type "help" for help. postgres=# CREATE USER keatest_readonly WITH PASSWORD 'keatest'; CREATE ROLE postgres=# \q $ psql -U keatest Password for user keatest: psql (9.1.12) Type "help" for help. keatest=> ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES to keatest_readonly; ALTER DEFAULT PRIVILEGES keatest=> \q @endverbatim Note that the keatest user (rather than postgres) is used to grant privileges to the keatest_readonly user. This ensures that the SELECT privilege is granted only on the tables that the keatest user can access within the public schema. Now we should be able to log into the newly created database using both user names: @verbatim $ psql -d keatest -U keatest Password for user keatest: psql (9.1.12) Type "help" for help. keatest=> \q $ psql -d keatest -U keatest_readonly Password for user keatest_readonly: psql (9.1.12) Type "help" for help. keatest=> @endverbatim If instead of seeing keatest=> prompt, your login is refused with an error code about failed peer or indent authentication, it means that PostgreSQL is configured to check unix username and reject login attempts if PostgreSQL names are different. To alter that, the PostgreSQL configuration must be changed - the /etc/postgresql/9.1/main/pg_hba.conf config file has to be altered. (It may be in a different location in your system.) The following lines: @verbatim local all all peer host all all 127.0.0.1/32 md5 host all all ::1/128 md5 @endverbatim need to be replaced with: @verbatim local all all password host all all 127.0.0.1/32 password host all all ::1/128 password @endverbatim Another possible problem is that you get no password prompt. This is most probably because you have no pg_hba.conf config file and everybody is by default trusted. As it has a very bad effect on the security you should have been warned this is a highly unsafe configuration. The solution is the same, i.e., require password or md5 authentication method. If you lose the postgres user access you can first add: @verbatim local all postgres trust @endverbatim to trust only the local postgres user. Note the postgres user can be pgsql on some systems. Please consult your PostgreSQL user manual before applying those changes as those changes may expose your other databases that you run on the same system. In general case, it is a poor idea to run anything of value on a system that runs tests. Use caution! The unit tests are run automatically when "make check" is executed (providing that Kea has been build with the \c --with-dhcp-pgsql switch (see the installation section in the Kea Administrator Reference Manual). @subsection cqlUnitTestsPrerequisites Cassandra database @todo: Describe steps necessary to set up Cassandra database suitable for running unittests. */ kea-1.1.0/doc/guide/0000775000175000017500000000000012772742656011140 500000000000000kea-1.1.0/doc/guide/Makefile.in0000664000175000017500000004644212772742613013130 00000000000000# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = doc/guide DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(dist_doc_DATA) $(dist_html_DATA) ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4macros/ax_boost_for_kea.m4 \ $(top_srcdir)/m4macros/ax_isc_rpath.m4 \ $(top_srcdir)/m4macros/libtool.m4 \ $(top_srcdir)/m4macros/ltoptions.m4 \ $(top_srcdir)/m4macros/ltsugar.m4 \ $(top_srcdir)/m4macros/ltversion.m4 \ $(top_srcdir)/m4macros/lt~obsolete.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(docdir)" "$(DESTDIR)$(htmldir)" DATA = $(dist_doc_DATA) $(dist_html_DATA) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ASCIIDOC = @ASCIIDOC@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BOOST_INCLUDES = @BOOST_INCLUDES@ BOOST_LIBS = @BOOST_LIBS@ BOTAN_TOOL = @BOTAN_TOOL@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CQL_CPPFLAGS = @CQL_CPPFLAGS@ CQL_LIBS = @CQL_LIBS@ CRYPTO_CFLAGS = @CRYPTO_CFLAGS@ CRYPTO_INCLUDES = @CRYPTO_INCLUDES@ CRYPTO_LDFLAGS = @CRYPTO_LDFLAGS@ CRYPTO_LIBS = @CRYPTO_LIBS@ CRYPTO_PACKAGE = @CRYPTO_PACKAGE@ CRYPTO_RPATH = @CRYPTO_RPATH@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DBLATEX = @DBLATEX@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DISTCHECK_BOOST_CONFIGURE_FLAG = @DISTCHECK_BOOST_CONFIGURE_FLAG@ DISTCHECK_CRYPTO_CONFIGURE_FLAG = @DISTCHECK_CRYPTO_CONFIGURE_FLAG@ DISTCHECK_GTEST_CONFIGURE_FLAG = @DISTCHECK_GTEST_CONFIGURE_FLAG@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ ELINKS = @ELINKS@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GENHTML = @GENHTML@ GREP = @GREP@ GTEST_CONFIG = @GTEST_CONFIG@ GTEST_INCLUDES = @GTEST_INCLUDES@ GTEST_LDADD = @GTEST_LDADD@ GTEST_LDFLAGS = @GTEST_LDFLAGS@ GTEST_SOURCE = @GTEST_SOURCE@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ KEA_CXXFLAGS = @KEA_CXXFLAGS@ LCOV = @LCOV@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LEXLIB = @LEXLIB@ LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LOG4CPLUS_INCLUDES = @LOG4CPLUS_INCLUDES@ LOG4CPLUS_LIBS = @LOG4CPLUS_LIBS@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ MYSQL_LIBS = @MYSQL_LIBS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PERL = @PERL@ PGSQL_CPPFLAGS = @PGSQL_CPPFLAGS@ PGSQL_LIBS = @PGSQL_LIBS@ PKG_CONFIG = @PKG_CONFIG@ PLANTUML = @PLANTUML@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SEP = @SEP@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ USE_LCOV = @USE_LCOV@ VALGRIND = @VALGRIND@ VERSION = @VERSION@ WARNING_GCC_44_STRICT_ALIASING_CFLAG = @WARNING_GCC_44_STRICT_ALIASING_CFLAG@ XSLTPROC = @XSLTPROC@ YACC = @YACC@ YFLAGS = @YFLAGS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ # generated documentation HTMLDOCS = kea-guide.html kea-messages.html DOCS = kea-guide.txt dist_doc_DATA = $(DOCS) dist_html_DATA = $(HTMLDOCS) kea-guide.css kea-logo-100x70.png DOCBOOK = kea-guide.xml intro.xml quickstart.xml install.xml admin.xml \ config.xml keactrl.xml dhcp4-srv.xml dhcp6-srv.xml \ lease-expiration.xml logging.xml ddns.xml hooks.xml \ libdhcp.xml lfc.xml stats.xml ctrl-channel.xml faq.xml \ classify.xml EXTRA_DIST = $(DOCBOOK) DISTCLEANFILES = $(HTMLDOCS) $(DOCS) kea-messages.xml @HAVE_DBLATEX_TRUE@CLEANFILES = kea-guide.pdf kea-messages.pdf @HAVE_DBLATEX_TRUE@DBLATEX_FLAGS = --xslt-opts=--path --xslt-opts=$(abs_top_builddir)/doc \ @HAVE_DBLATEX_TRUE@ -P doc.collab.show=0 -P latex.output.revhistory=0 \ @HAVE_DBLATEX_TRUE@ -P term.breakline=1 -P filename.as.url=0 \ @HAVE_DBLATEX_TRUE@ -P imagedata.default.scale="maxwidth=50px,maxheigth=35px" all: all-am .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign doc/guide/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign doc/guide/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-dist_docDATA: $(dist_doc_DATA) @$(NORMAL_INSTALL) @list='$(dist_doc_DATA)'; test -n "$(docdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(docdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(docdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(docdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(docdir)" || exit $$?; \ done uninstall-dist_docDATA: @$(NORMAL_UNINSTALL) @list='$(dist_doc_DATA)'; test -n "$(docdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(docdir)'; $(am__uninstall_files_from_dir) install-dist_htmlDATA: $(dist_html_DATA) @$(NORMAL_INSTALL) @list='$(dist_html_DATA)'; test -n "$(htmldir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(htmldir)'"; \ $(MKDIR_P) "$(DESTDIR)$(htmldir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(htmldir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(htmldir)" || exit $$?; \ done uninstall-dist_htmlDATA: @$(NORMAL_UNINSTALL) @list='$(dist_html_DATA)'; test -n "$(htmldir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(htmldir)'; $(am__uninstall_files_from_dir) tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(DATA) installdirs: for dir in "$(DESTDIR)$(docdir)" "$(DESTDIR)$(htmldir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dist_docDATA install-dist_htmlDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool @HAVE_DBLATEX_FALSE@pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-dist_docDATA uninstall-dist_htmlDATA .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am \ install-dist_docDATA install-dist_htmlDATA install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags-am uninstall uninstall-am uninstall-dist_docDATA \ uninstall-dist_htmlDATA kea-messages.xml: $(top_srcdir)/tools/system_messages -o $@ \ `find $(top_srcdir) -name "*.mes" -print` # This is not a "man" manual, but reuse this for now for docbook. @GENERATE_DOCS_TRUE@kea-guide.html: $(DOCBOOK) @GENERATE_DOCS_TRUE@ @XSLTPROC@ --novalid --xinclude --nonet \ @GENERATE_DOCS_TRUE@ --path $(top_builddir)/doc \ @GENERATE_DOCS_TRUE@ -o $@ \ @GENERATE_DOCS_TRUE@ --stringparam section.autolabel 1 \ @GENERATE_DOCS_TRUE@ --stringparam section.label.includes.component.label 1 \ @GENERATE_DOCS_TRUE@ --stringparam html.stylesheet kea-guide.css \ @GENERATE_DOCS_TRUE@ http://docbook.sourceforge.net/release/xsl/current/html/docbook.xsl \ @GENERATE_DOCS_TRUE@ $(srcdir)/kea-guide.xml @GENERATE_DOCS_TRUE@kea-guide.txt: kea-guide.html @GENERATE_DOCS_TRUE@ @ELINKS@ -dump -no-numbering -no-references kea-guide.html > $@ @GENERATE_DOCS_TRUE@kea-messages.html: kea-messages.xml @GENERATE_DOCS_TRUE@ @XSLTPROC@ --novalid --xinclude --nonet \ @GENERATE_DOCS_TRUE@ --path $(top_builddir)/doc \ @GENERATE_DOCS_TRUE@ -o $@ \ @GENERATE_DOCS_TRUE@ --stringparam generate.toc "book toc" \ @GENERATE_DOCS_TRUE@ --stringparam html.stylesheet kea-guide.css \ @GENERATE_DOCS_TRUE@ http://docbook.sourceforge.net/release/xsl/current/html/docbook.xsl \ @GENERATE_DOCS_TRUE@ kea-messages.xml @GENERATE_DOCS_FALSE@$(HTMLDOCS) $(DOCS): @GENERATE_DOCS_FALSE@ @echo Doc generation disabled. Creating dummy $@. Configure with --enable-generate-docs to enable it. @GENERATE_DOCS_FALSE@ @echo Doc generation disabled. Remove this file, configure with --enable-generate-docs, and rebuild Kea > $@ @HAVE_DBLATEX_TRUE@pdf: kea-guide.pdf kea-messages.pdf @HAVE_DBLATEX_TRUE@kea-guide.pdf: $(DOCBOOK) @HAVE_DBLATEX_TRUE@ @DBLATEX@ $(DBLATEX_FLAGS) kea-guide.xml @HAVE_DBLATEX_TRUE@kea-messages.pdf: kea-messages.xml @HAVE_DBLATEX_TRUE@ @DBLATEX@ $(DBLATEX_FLAGS) kea-messages.xml @HAVE_DBLATEX_FALSE@pdf kea-guide.pdf kea-messages.pdf: @HAVE_DBLATEX_FALSE@ @echo Install dblatex tool and rerun ./configure to be able to generate documentation in PDF format. # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: kea-1.1.0/doc/guide/kea-guide.xml0000664000175000017500000001160612772445242013430 00000000000000 %version; ]> <inlinemediaobject> <imageobject> <imagedata fileref="kea-logo-100x70.png" align="left"/> </imageobject> </inlinemediaobject> Kea Administrator Reference Manual This is the reference guide for Kea version &__VERSION__;. 2010-2016Internet Systems Consortium, Inc. Kea is an open source implementation of the Dynamic Host Configuration Protocol (DHCP) servers, developed and maintained by Internet Systems Consortium (ISC). This is the reference guide for Kea version &__VERSION__;. The most up-to-date version of this document (in PDF, HTML, and plain text formats), along with other documents for Kea, can be found at . Acknowledgments Kea is primarily designed, developed, and maintained by Internet Systems Consortium, Inc. It is an open source project and contributions are welcomed. Support for the development of the DHCPv4, DHCPv6 and DHCP-DDNS components was provided by Comcast. Kea was initially implemented as a collection of applications within the BIND 10 framework. Hence, Kea development would not be possible without the generous support of past BIND 10 project sponsors. JPRS and CIRA were Patron Level BIND 10 sponsors. AFNIC, CNNIC, CZ.NIC, DENIC eG, Google, RIPE NCC, Registro.br, .nz Registry Services, and Technical Center of Internet were past BIND 10 sponsors. Afilias, IIS.SE, Nominet, and SIDN were founding sponsors of the BIND 10 project. kea-1.1.0/doc/guide/kea-guide.css0000664000175000017500000000160012772017075013410 00000000000000body { background-color: #ffffff; color: #333333; font-family: "ArialMT", "Verdana", "Arial", "Helvetica", sans-serif; font-size: 14px; line-height: 18px; margin: 2em; } .command { font-family: "Courier New", "Courier", monospace; font-weight: normal; } .note { background-color: #ddeedd; border: 1px solid #aaccaa; margin: 1em 0 1em 0; padding: 0.5em 1em 0.5em 1em; -moz-border-radius: 10px; -webkit-border-radius: 10px; } .screen { background-color: #ffffee; border: 1px solid #ddddaa; padding: 0.25em 1em 0.25em 1em; margin: 1em 0 1em 0; -moz-border-radius: 10px; -webkit-border-radius: 10px; } .warning { background-color: #eedddd; border: 1px solid #ccaaaa; margin: 1em 0 1em 0; padding: 0.5em 1em 0.5em 1em; -moz-border-radius: 10px; -webkit-border-radius: 10px; } h3 { text-decoration: underline; } h4 { text-decoration: underline; font-weight: normal; }kea-1.1.0/doc/guide/quickstart.xml0000664000175000017500000001170512772445242013767 00000000000000 %version; ]> Quick Start This section describes the basic steps needed to get Kea up and running. For further details, full customizations, and troubleshooting, see the respective chapters in the Kea guide.
Quick Start Guide for DHCPv4 and DHCPv6 Services Install required run-time and build dependencies. See for details. Download Kea source tarball from ISC.org downloads page or ISC ftp server. Extract the tarball. For example: $ tar xvzf kea-&__VERSION__;.tar.gz Go into the source directory and run the configure script: $ cd kea-&__VERSION__; $ ./configure [your extra parameters] Build it: $ make Install it (by default it will be placed in /usr/local/, so it is likely that you will need root privileges for this step): # make install Edit the configuration file which by default is installed in [kea-install-dir]/etc/kea/kea.conf and contains configuration for all Kea services. Configuration choices for DHCPv4 and DHCPv6 services are described in and :w respectively. In order to start the DHCPv4 server in background, run the following command (as root): # keactrl start -s dhcp4 Or run the following command to start DHCPv6 server instead: # keactrl start -s dhcp6 Note that it is also possible to start both servers simultaneously: $ keactrl start Verify that Kea server(s) are running: # keactrl status A server status of "inactive" may indicate a configuration error. Please check the log file (by default named [kea-install-dir]/var/kea/kea-dhcp4.log or [kea-install-dir]/var/kea/kea-dhcp6.log) for the details of the error. If the server has been started successfully, test that it is responding to DHCP queries and that the client receives a configuration from the server; for example, use the ISC DHCP client. Stop running the server(s): # keactrl stop For instructions specific to your system, please read the system specific notes, available on the Kea web site. The details of keactrl script usage can be found in .
Running the Kea Servers Directly The Kea servers can be started directly, without the need to use the keactrl. To start the DHCPv4 server run the following command: # kea-dhcp4 -c /path/to/your/kea4/config/file.json Similarly, to start the DHCPv6 server run the following command: # kea-dhcp6 -c /path/to/your/kea6/config/file.json
kea-1.1.0/doc/guide/hooks.xml0000664000175000017500000005757312772445242012735 00000000000000 ]> Hooks Libraries
Introduction Although Kea offers a lot of flexibility, there may be cases where its behavior needs customisation. To accommodate this possibility, Kea includes the idea of "Hooks". This feature lets Kea load one or more dynamically-linked libraries (known as "hooks libraries") and, at various points in its processing ("hook points"), call functions in them. Those functions perform whatever custom processing is required. Hooks libraries are attached to individual Kea processes, not to Kea as a whole. This means (for example) that it is possible to associate one set of libraries with the DHCP4 server and a different set to the DHCP6 server. Another point to note is that it is possible for a process to load multiple libraries. When processing reaches a hook point, Kea calls the hooks library functions attached to it. If multiple libraries have attached a function to a given hook point, Kea calls all of them, in the order in which the libraries are specified in the configuration file. The order may be important: consult the documentation of the libraries to see if this is the case. The next section describes how to configure hooks libraries. If you are interested in writing your own hooks library, information can be found in the Kea Developer's Guide.
Configuring Hooks Libraries The hooks libraries for a given process are configured using the hooks-libraries keyword in the configuration for that process. (Note that the word "hooks" is plural). The value of the keyword is an array of map structures, each structure corresponding to a hooks library. For example, to set up two hooks libraries for the DHCPv4 server, the configuration would be: "Dhcp4": { : "hooks-libraries": [ { "library": "/opt/charging.so" }, { "library": "/opt/local/notification.so", "parameters": { "mail": "spam@example.com", "floor": 13, "debug": false, "users": [ "alice", "bob", "charlie" ], "languages": { "french": "bonjour", "klingon": "yl'el" } } } ] : } This is a change to the syntax used in Kea 0.9.2 and earlier, where hooks-libraries was a list of strings, each string being the name of a library. The change was made in Kea 1.0 to facilitate the specification of library-specific parameters, a capability available in Kea 1.1.0 onwards. The library reloading behavior has changed in Kea 1.1. Libraries are reloaded, even if their list hasn't changed. Kea does that, because the parameters specified for the library (or the files those parameters point to) may have changed. Libraries may have additional parameters. Those are not mandatory in the sense that there may be libraries that don't require them. However, for specific library there is often specific requirement for specify certain set of parameters. Please consult the documentation for your library for details. In the example above, the first library has no parameters. The second library has five parameters, specifying mail (string parameter), floor (integer parameter), debug (boolean parameter) and even lists (list of strings) and maps (containing strings). Nested parameters could be used if the library supports it. This topic is explained in detail in the Hooks Developer's Guide in the "Configuring Hooks Libraries" section. Notes: The full path to each library should be given. As noted above, order may be important - consult the documentation for each library. An empty list has the same effect as omitting the hooks-libraries configuration element all together. There is one case where this is not true: if Kea is running with a configuration that contains a hooks-libraries item, and that item is removed and the configuration reloaded, the removal will be ignored and the libraries remain loaded. As a workaround, instead of removing the hooks-libraries item, change it to an empty list. This will be fixed in a future version of Kea. At the present time, only the kea-dhcp4 and kea-dhcp6 processes support hooks libraries.
Available Hooks Libraries As described above, the hooks functionality provides a way to customize a Kea server without modifying the core code. ISC has chosen to take advantage of this feature to provide functions that may only be useful to a subset of Kea users. To this end ISC has created some hooks libraries; these discussed in the following sections. Some of these libraries will be available with the base code while others will be shared with organizations supporting development of Kea , possibly as a 'benefit' or 'thank you' for helping to sustain the larger Kea project. If you would like to get access to those libraries, please consider taking out a support contract: this includes professional support, advance security notifications, input into our roadmap planning, and many other benefits, while helping making Kea sustainable in the long term. Currently the following libraries are available or planned from ISC: List of available hooks libraries Name Availability Since Description user_chk Kea sources Kea 0.8 Reads known users list from a file. Unknown users will be assigned a lease from the last subnet defined in the configuration file, e.g. to redirect them a captive portal. This demonstrates how an external source of information can be used to influence the Kea allocation engine. This hook is part of the Kea source code and is available in the src/hooks/dhcp/user_chk directory. Forensic Logging Support customers Kea 1.1.0 This library provides hooks that record a detailed log of lease assignments and renewals into a set of log files. In many legal jurisdictions companies, especially ISPs, must record information about the addresses they have leased to DHCP clients. This library is designed to help with that requirement. If the information that it records is sufficient it may be used directly. If your jurisdiction requires that you save a different set of information, you may use it as a template or example and create your own custom logging hooks. Lightweight 4over6 Support customers Autumn 2016 Lightweight 4over6 (RFC 7596) is a new IPv6 transition technology that provides IPv4 as a service in IPv6-only network. It assumes that dual-stack clients will get a regular IPv6 address and IPv6 prefix, but only a fraction of an IPv4 address. The fraction is specified as port-set, which is essentially a range of TCP and UDP ports a client can use. By doing the transition on the client side, this technology eliminates the need to deploy expensive Carrier Grade NATs within the operator's network. The problem on the DHCP side is the non-trivial logic behind it: each client needs to receive an unique set of lightweight 4over6 options (RFC 7598), that include the IPv4 address (shared among several clients), port-set (which is unique among clients sharing the same IPv4 address) and a number of additional parameters. This hooks library will generate values of those options dynamically, thus eliminating the need to manually configure values for each client separately.
ISC hopes to see more hooks libraries become available as time progresses, both developed internally and externally. Since this list may evolve dynamically, we decided to keep it on a wiki page, available at this link: http://kea.isc.org/wiki/Hooks. If you are a developer or are aware of any hooks libraries not listed there, please send a note to the kea-users or kea-dev mailing lists and someone will update it.
user_chk: Checking User Access The user_chk library is the first hooks library published by ISC. It attempts to serve several purposes: To assign "new" or "unregistered" users to a restricted subnet, while "known" or "registered" users are assigned to unrestricted subnets. To allow DHCP response options or vendor option values to be customized based upon user identity. To provide a real time record of the user registration activity which can be sampled by an external consumer. To serve as a demonstration of various capabilities possible using the hooks interface. Once loaded, the library allows segregating incomings requests into known and unknown clients. For known clients, the packets are processed mostly as usual, except it is possible to override certain options being sent. That can be done on a per host basis. Clients that are not on the known hosts list will be treated as unknown and will be assigned to the last subnet defined in the configuration file. As an example of use, this behavior may be used to put unknown users into a separate subnet that leads to a walled garden, where they can only access a registration portal. Once they fill in necessary data, their details are added to the known clients file and they get a proper address after their device is restarted. This library was developed several years before the host reservation mechanism has become available. Currently host reservation is much more powerful and flexible, but nevertheless the user_chk capability to consult and external source of information about clients and alter Kea's behavior is useful and remains of educational value. The library reads the /tmp/user_chk_registry.txt file while being loaded and each time an incoming packet is processed. The file is expected to have each line contain a self-contained JSON snippet which must have the following two entries: type, whose value is "HW_ADDR" for IPv4 users or "DUID" for IPv6 users id, whose value is either the hardware address or the DUID from the equest formatted as a string of hex digits, with or without ":" delimiters. and may have the zero or more of the following entries: bootfile whose value is the pathname of the desired file tftp_server whose value is the hostname or IP address of the desired server A sample user registry file is shown below: { "type" : "HW_ADDR", "id" : "0c:0e:0a:01:ff:04", "bootfile" : "/tmp/v4bootfile" } { "type" : "HW_ADDR", "id" : "0c:0e:0a:01:ff:06", "tftp_server" : "tftp.v4.example.com" } { "type" : "DUID", "id" : "00:01:00:01:19:ef:e6:3b:00:0c:01:02:03:04", "bootfile" : "/tmp/v6bootfile" } { "type" : "DUID", "id" : "00:01:00:01:19:ef:e6:3b:00:0c:01:02:03:06", "tftp_server" : "tftp.v6.example.com" } As with any other hooks libraries provided by ISC, internals of the user_chk code are well documented. You can take a look at the Kea Developer's Guide section dedicated to the user_chk library that discusses how the code works internally. That, together with our general entries in Hooks Framework section should give you some pointers how to extend this library and perhaps even write your own from scratch.
Forensic Logging Hooks This section describes the forensic log hooks library. This library povides hooks that record a detailed log of lease assignments and renewals into a set of log files. Currently this library is only available to ISC customers with a support contract. In many legal jurisdictions companies, especially ISPs, must record information about the addresses they have leased to DHCP clients. This library is designed to help with that requirement. If the information that it records is sufficient it may be used directly. If your jurisdiction requires that you save a different set of information you may use it as a template or example and create your own custom logging hooks. This logging is done as a set of hooks to allow it to be customized to any particular need. Modifying a hooks library is easier and safer than updating the core code. In addition by using the hooks features those users who don't need to log this information can leave it out and avoid any performance penalties.
Log File Naming The names for the log files have the following form: path/base-name.CCYYMMDD.txt The "path" and "base-name" are supplied in the configuration as described below see . The next part of the name is the date the log file was started, with four digits for year, two digits for month and two digits for day. The file is rotated on a daily basis. When running Kea servers for both DHCPv4 and DHCPv6 the log names must be distinct. See the examples in .
DHCPv4 Log Entries For DHCPv4 the library creates entries based on DHCPREQUEST messages and corresponding DHCPv4 leases intercepted by lease4_select (for new leases) and lease4_renew (for renewed leases) hooks. An entry is a single string with no embedded end-of-line markers and has the following sections: address duration device-id {client-info} {relay-info} Where: address - the leased IPv4 address given out and whether it was assigned or renewed. duration - the lease lifetime expressed in days (if present), hours, minutes and seconds. A lease lifetime of 0xFFFFFFFF will be denoted with the text "infinite duration". device-id - the client's hardware address shown as numerical type and hex digit string. client-info - the DHCP client id option (61) if present, shown as a hex string. relay-info - for relayed packets the giaddr and the RAI circuit id and remote id options (option 82 sub options 1 and 2) if present. The circuit id and remote id are presented as hex strings For instance (line breaks added for readability, they would not be present in the log file). Address: 192.2.1.100 has been renewed for 1 hrs 52 min 15 secs to a device with hardware address: hwtype=1 08:00:2b:02:3f:4e, client-id: 17:34:e2:ff:09:92:54 connected via relay at address: 192.2.16.33, identified by circuit-id: 68:6f:77:64:79 and remote-id: 87:f6:79:77:ef
DHCPv6 Log Entries For DHCPv6 the library creates entries based on lease management actions intercepted by the lease6_select (for new leases), lease6_renew (for renewed leases) and lease6_rebind (for rebound leases). An entry is a single string with no embedded end-of-line markers and has the following sections: address duration device-id {relay-info}* Where: address - the leased IPv6 address or prefix given out and whether it was assigned or renewed. duration - the lease lifetime expressed in days (if present), hours, minutes and seconds. A lease lifetime of 0xFFFFFFFF will be denoted with the text "infinite duration". device-id - the client's DUID and hardware address (if present). relay-info - for relayed packets the content of relay agent messages, remote id and subscriber id options (x and xx) if present. For instance (line breaks added for readability, they would not be present in the log file). Address:2001:db8:1:: has been assigned for 0 hrs 11 mins 53 secs to a device with DUID: 17:34:e2:ff:09:92:54 and hardware address: hwtype=1 08:00:2b:02:3f:4e (from Raw Socket) connected via relay at address: fe80::abcd for client on link address: 3001::1, hop count: 1, identified by remote-id: 01:02:03:04:0a:0b:0c:0d:0e:0f and subscriber-id: 1a:2b:3c:4d:5e:6f
Configuring the Forensic Log Hooks To use this functionality the hook library must be included in the configuration of the desired DHCP server modules. The legal_log library is installed alongside the Kea libraries in [kea-install-dir]/lib where kea-install-dir is determined by the "--prefix" option of the configure script. It defaults to /usr/local. Assuming the default value then, configuring kea-dhcp4 to load the legal_log library could be done with the following Kea4 configuration: "Dhcp4": { "hooks-libraries": [ { "library": "/usr/local/lib/libdhcp_legal_log.so", "parameters": { "path": "/var/kea/var", "base-name": "kea-forensic4" } }, ... ] } To configure it for kea-dhcp6, the commands are simply as shown below: "Dhcp6": { "hooks-libraries": [ { "library": "/usr/local/lib/libdhcp_legal_log.so", "parameters": { "path": "/var/kea/var", "base-name": "kea-forensic6" } }, ... ] } Two Hook Library parameters are supported: path - the directory in which the forensic file(s) will be written. The default value is [prefix]/kea/var. The directory must exist. base-name - an arbitrary value which is used in conjunction with the current system date to form the current foresnic file name. It defaults to kea-legal.
kea-1.1.0/doc/guide/lfc.xml0000664000175000017500000001066512772445242012345 00000000000000 ]> The LFC process
Overview kea-lfc is a service process that removes redundant information from the files used to provide persistent storage for the memfile data base backend. This service is written to run as a stand alone process. While kea-lfc can be started externally, there is usually no need to do this. kea-lfc is run on a periodic basis by the Kea DHCP servers. The process operates on a set of files, using them for input and output of the lease entries and to indicate where it is in the process in case of an interruption. Currently the caller must supply names for all of the files, in the future this requirement may be relaxed with the process getting the names from either the configuration file or from defaults.
Command Line Options kea-lfc is run as follows: kea-lfc [-4 | -6] -c config-file -p pid-file -x previous-file -i copy-file -o output-file -f finish-file The argument -4 or -6 selects the protocol version of the lease files. The -c argument specifies the configuration file. This is required, but not currently used by the process. The -p argument specifies the PID file. When the kea-lfc process starts it attempts to determine if another instance of the process is already running by examining the pid file. If one is already running the new process is terminated. If one isn't running it writes its pid into the pid file. The other filenames specify where the kea-lfc process should look for input, write its output and use for bookkeeping. previous — When kea-lfc starts this is the result of any previous run of kea-lfc. When kea-lfc finishes it is the result of this run. If kea-lfc is interrupted before completing, this file may not exist. input — Before the DHCP server invokes kea-lfc it will move the current lease file here and then call kea-lfc with this file. output — The temporary file kea-lfc should use to write the leases. Upon completion of writing this file, it will be moved to the finish file (see below). finish — Another temporary file kea-lfc uses for bookkeeping. When kea-lfc completes writing the outputfile it moves it to this file name. After kea-lfc finishes deleting the other files (previous and input) it moves this file to previous lease file. By moving the files in this fashion the kea-lfc and the DHCP server processes can determine the correct file to use even if one of the processes was interrupted before completing its task. There are several additional arguments mostly for debugging purposes. -d Sets the logging level to debug. -v and -V print out version stamps with -V providing a longer form. -h prints out the usage string.
kea-1.1.0/doc/guide/ddns.xml0000664000175000017500000007522212772445242012531 00000000000000 ]> The DHCP-DDNS Server The DHCP-DDNS Server (kea-dhcp-ddns, known informally as D2) conducts the client side of the DDNS protocol (defined in RFC 2136) on behalf of the DHCPv4 and DHCPv6 servers (kea-dhcp4 and kea-dhcp6 respectively). The DHCP servers construct DDNS update requests, known as NameChangeRequests (NCRs), based upon DHCP lease change events and then post these to D2. D2 attempts to match each such request to the appropriate DNS server(s) and carry out the necessary conversation with those servers to update the DNS data. In order to match a request to the appropriate DNS servers, D2 must have a catalog of servers from which to select. In fact, D2 has two such catalogs, one for forward DNS and one for reverse DNS; these catalogs are referred to as DDNS Domain Lists. Each list consists of one or more named DDNS Domains. Further, each DDNS Domain has a list of one or more DNS servers that publish the DNS data for that domain. When conducting forward domain matching, D2 will compare the FQDN in the request against the name of each forward DDNS Domain. The domain whose name matches the longest portion of the FQDN is considered the best match. For example, if the FQDN is "myhost.sample.example.com.", and there are two forward domains in the catalog: "sample.example.com." and "example.com.", the former is regarded as the best match. In some cases, it may not be possible to find a suitable match. Given the same two forward domains there would be no match for the FQDN, "bogus.net", so the request would be rejected. Finally, if there are no forward DDNS Domains defined, D2 will simply disregard the forward update portion of requests. When conducting reverse domain matching, D2 constructs a reverse FQDN from the lease address in the request and compare that against the name of each reverse DDNS Domain. Again, the domain whose name matches the longest portion of the FQDN is considered the best match. For instance, if the lease address is "172.16.1.40" and there are two reverse domains in the catalog: "1.16.172.in-addr.arpa." and "16.172.in-addr.arpa", the former is the best match. As with forward matching, it is possible to not find a suitable match. Given the same two domains, there would be no match for the lease address, "192.168.1.50", and the request would be rejected. Finally, if there are no reverse DDNS Domains defined, D2 will simply disregard the reverse update portion of requests.
Starting and Stopping the DHCP-DDNS Server kea-dhcp-ddns is the Kea DHCP-DDNS server and, due to the nature of DDNS, it is run alongside either the DHCPv4 or DHCPv6 components (or both). Like other parts of Kea, it is a separate binary that can be run on its own or through keactrl (see ). In normal operation, controlling kea-dhcp-ddns with keactrl is recommended. However, it is also possible to run the DHCP-DDNS server directly. It accepts the following command-line switches: -c file - specifies the configuration file. This is the only mandatory switch. -d - specifies whether the server logging should be switched to debug/verbose mode. In verbose mode, the logging severity and debuglevel specified in the configuration file are ignored and "debug" severity and the maximum debuglevel (99) are assumed. The flag is convenient, for temporarily switching the server into maximum verbosity, e.g. when debugging. -v - prints out Kea version and exits. -W - prints out the Kea configuration report and exits. The report is a copy of the config.report file produced by ./configure: it is embedded in the executable binary. -W - prints out Kea configuration report and exits. The config.report may also be accessed more directly. The following command may be used to extract this information. The binary path may be found in the install directory or in the .libs subdirectory in the source tree. For example kea/src/bin/d2/.libs/kea-dhcp-ddns. strings path/kea-dhcp-ddns | sed -n 's/;;;; //p' Upon start up the module will load its configuration and begin listening for NCRs based on that configuration. During startup the server will attempt to create a PID file of the form: [localstatedir]/[conf name].kea-dhcp-ddns.pid where: localstatedir: The value as passed into the build configure script. It defaults to "/usr/local/var". Note that this value may be overridden at run time by setting the environment variable KEA_PIDFILE_DIR. This is intended primarily for testing purposes. conf name: The configuration file name used to start the server, minus all preceding path and file extension. For example, given a pathname of "/usr/local/etc/kea/myconf.txt", the portion used would be "myconf". If the file already exists and contains the PID of a live process, the server will issue a DHCP_DDNS_ALREADY_RUNNING log message and exit. It is possible, though unlikely, that the file is a remnant of a system crash and the process to which the PID belongs is unrelated to Kea. In such a case it would be necessary to manually delete the PID file.
Configuring the DHCP-DDNS Server Before starting kea-dhcp-ddns module for the first time, a configuration file needs to be created. The following default configuration is a template that can be customised to your requirements. "DhcpDdns": { "ip-address": "127.0.0.1", "port": 53001, "dns-server-timeout": 100, "ncr-protocol": "UDP", "ncr-format": "JSON", "tsig-keys": [ ], "forward-ddns": { "ddns-domains": [ ] }, "reverse-ddns": { "ddns-domains": [ ] } } The configuration can be divided as follows, each of which is described in its own section: Global Server Parameters - values which control connectivity and global server behavior TSIG Key Info - defines the TSIG keys used for secure traffic with DNS servers Forward DDNS - defines the catalog of Forward DDNS Domains Reverse DDNS - defines the catalog of Forward DDNS Domains
Global Server Parameters ip-address - IP address on which D2 listens for requests. The default is the local loopback interface at address 127.0.0.1. You may specify either an IPv4 or IPv6 address. port - Port on which D2 listens for requests. The default value is 53001. dns-server-timeout - The maximum amount of time in milliseconds, that D2 will wait for a response from a DNS server to a single DNS update message. ncr-protocol - Socket protocol to use when sending requests to D2. Currently only UDP is supported. TCP may be available in a future release. ncr-format - Packet format to use when sending requests to D2. Currently only JSON format is supported. Other formats may be available in future releases. D2 must listen for change requests on a known address and port. By default it listens at 127.0.0.1 on port 53001. The following example illustrates how to change D2's global parameters so it will listen at 192.168.1.10 port 900: "DhcpDdns": { "ip-address": "192.168.1.10", "port": 900, ... } } It is possible for a malicious attacker to send bogus NameChangeRequests to the DHCP-DDNS server. Addresses other than the IPv4 or IPv6 loopback addresses (127.0.0.1 or ::1) should only be used for testing purposes, but note that local users may still communicate with the DHCP-DDNS server. A future version of Kea will implement authentication to guard against such attacks. If the ip-address and port are changed, it will be necessary to change the corresponding values in the DHCP servers' "dhcp-ddns" configuration section.
TSIG Key List A DDNS protocol exchange can be conducted with or without TSIG (defined in RFC 2845). This configuration section allows the administrator to define the set of TSIG keys that may be used in such exchanges. To use TSIG when updating entries in a DNS Domain, a key must be defined in the TSIG Key List and referenced by name in that domain's configuration entry. When D2 matches a change request to a domain, it checks whether the domain has a TSIG key associated with it. If so, D2 will use that key to sign DNS update messages sent to and verify responses received from the domain's DNS server(s). For each TSIG key required by the DNS servers that D2 will be working with there must be a corresponding TSIG key in the TSIG Key list. As one might gather from the name, the tsig-key section of the D2 configuration lists the TSIG keys. Each entry describes a TSIG key used by one or more DNS servers to authenticate requests and sign responses. Every entry in the list has three parameters: name - a unique text label used to identify this key within the list. This value is used to specify which key (if any) should be used when updating a specific domain. So long as it is unique its content is arbitrary, although for clarity and ease of maintenance it is recommended that it match the name used on the DNS server(s). It cannot be blank. algorithm - specifies which hashing algorithm should be used with this key. This value must specify the same algorithm used for the key on the DNS server(s). The supported algorithms are listed below: HMAC-MD5 HMAC-SHA1 HMAC-SHA224 HMAC-SHA256 HMAC-SHA384 HMAC-SHA512 This value is not case sensitive. digest-bits - is used to specify the minimum truncated length in bits. The default value 0 means truncation is forbidden, non-zero values must be an integral number of octets, be greater than 80 and the half of the full length. Note in BIND9 this parameter is appended after a dash to the algorithm name. secret - is used to specify the shared secret key code for this key. This value is case sensitive and must exactly match the value specified on the DNS server(s). It is a base64-encoded text value. As an example, suppose that a domain D2 will be updating is maintained by a BIND9 DNS server which requires dynamic updates to be secured with TSIG. Suppose further that the entry for the TSIG key in BIND9's named.conf file looks like this: : key "key.four.example.com." { algorithm hmac-sha224; secret "bZEG7Ow8OgAUPfLWV3aAUQ=="; }; : By default, the TSIG Key list is empty: "DhcpDdns": { "tsig-keys": [ ], ... } We must extend the list with a new key: "DhcpDdns": { "tsig-keys": [ { "name": "key.four.example.com.", "algorithm": "HMAC-SHA224", "secret": "bZEG7Ow8OgAUPfLWV3aAUQ==" } ], ... } These steps would be repeated for each TSIG key needed. Note that the same TSIG key can be used with more than one domain.
Forward DDNS The Forward DDNS section is used to configure D2's forward update behavior. Currently it contains a single parameter, the catalog of forward DDNS Domains, which is a list of structures. "DhcpDdns": { "forward-ddns": { "ddns-domains": [ ] }, ... } By default, this list is empty, which will cause the server to ignore the forward update portions of requests.
Adding Forward DDNS Domains A forward DDNS Domain maps a forward DNS zone to a set of DNS servers which maintain the forward DNS data (i.e. name to address mapping) for that zone. You will need one forward DDNS Domain for each zone you wish to service. It may very well be that some or all of your zones are maintained by the same servers. You will still need one DDNS Domain per zone. Remember that matching a request to the appropriate server(s) is done by zone and a DDNS Domain only defines a single zone. This section describes how to add Forward DDNS Domains. Repeat these steps for each Forward DDNS Domain desired. Each Forward DDNS Domain has the following parameters: name - The fully qualified domain name (or zone) that this DDNS Domain can update. This is value used to compare against the request FQDN during forward matching. It must be unique within the catalog. key-name - If TSIG is used with this domain's servers, this value should be the name of the key from within the TSIG Key List to use. If the value is blank (the default), TSIG will not be used in DDNS conversations with this domain's servers. dns-servers - A list of one or more DNS servers which can conduct the server side of the DDNS protocol for this domain. The servers are used in a first to last preference. In other words, when D2 begins to process a request for this domain it will pick the first server in this list and attempt to communicate with it. If that attempt fails, it will move to next one in the list and so on until the it achieves success or the list is exhausted. To create a new forward DDNS Domain, one must add a new domain element and set its parameters: "DhcpDdns": { "forward-ddns": { "ddns-domains": [ { "name": "other.example.com.", "key-name": "", "dns-servers": [ ] } ] } } It is permissible to add a domain without any servers. If that domain should be matched to a request, however, the request will fail. In order to make the domain useful though, we must add at least one DNS server to it.
Adding Forward DNS Servers This section describes how to add DNS servers to a Forward DDNS Domain. Repeat them for as many servers as desired for a each domain. Forward DNS Server entries represent actual DNS servers which support the server side of the DDNS protocol. Each Forward DNS Server has the following parameters: hostname - The resolvable host name of the DNS server. This value is not yet implemented. ip-address - The IP address at which the server listens for DDNS requests. This may be either an IPv4 or an IPv6 address. port - The port on which the server listens for DDNS requests. It defaults to the standard DNS service port of 53. To create a new forward DNS Server, one must add a new server element to the domain and fill in its parameters. If for example the service is running at "172.88.99.10", then set it as follows: "DhcpDdns": { "forward-ddns": { "ddns-domains": [ { "name": "other.example.com.", "key-name": "", "dns-servers": [ { "hostname": "", "ip-address": "172.88.99.10", "port": 53 } ] } ] } } As stated earlier, "hostname" is not yet supported so, the parameter "ip-address" must be set to the address of the DNS server.
Reverse DDNS The Reverse DDNS section is used to configure D2's reverse update behavior, and the concepts are the same as for the forward DDNS section. Currently it contains a single parameter, the catalog of reverse DDNS Domains, which is a list of structures. "DhcpDdns": { "reverse-ddns": { "ddns-domains": [ ] } ... } By default, this list is empty, which will cause the server to ignore the reverse update portions of requests.
Adding Reverse DDNS Domains A reverse DDNS Domain maps a reverse DNS zone to a set of DNS servers which maintain the reverse DNS data (address to name mapping) for that zone. You will need one reverse DDNS Domain for each zone you wish to service. It may very well be that some or all of your zones are maintained by the same servers; even then, you will still need one DDNS Domain entry for each zone. Remember that matching a request to the appropriate server(s) is done by zone and a DDNS Domain only defines a single zone. This section describes how to add Reverse DDNS Domains. Repeat these steps for each Reverse DDNS Domain desired. Each Reverse DDNS Domain has the following parameters: name - The fully qualified reverse zone that this DDNS Domain can update. This is the value used during reverse matching which will compare it with a reversed version of the request's lease address. The zone name should follow the appropriate standards: for example, to to support the IPv4 subnet 172.16.1, the name should be. "1.16.172.in-addr.arpa.". Similarly, to support an IPv6 subnet of 2001:db8:1, the name should be "1.0.0.0.8.B.D.0.1.0.0.2.ip6.arpa." Whatever the name, it must be unique within the catalog. key-name - If TSIG should be used with this domain's servers, then this value should be the name of that key from the TSIG Key List. If the value is blank (the default), TSIG will not be used in DDNS conversations with this domain's servers. Currently this value is not used as TSIG has not been implemented. dns-servers - a list of one or more DNS servers which can conduct the server side of the DDNS protocol for this domain. Currently the servers are used in a first to last preference. In other words, when D2 begins to process a request for this domain it will pick the first server in this list and attempt to communicate with it. If that attempt fails, it will move to next one in the list and so on until the it achieves success or the list is exhausted. To create a new reverse DDNS Domain, one must add a new domain element and set its parameters. For example, to support subnet 2001:db8:1::, the following configuration could be used: "DhcpDdns": { "reverse-ddns": { "ddns-domains": [ { "name": "1.0.0.0.8.B.D.0.1.0.0.2.ip6.arpa.", "key-name": "", "dns-servers": [ ] } ] } } It is permissible to add a domain without any servers. If that domain should be matched to a request, however, the request will fail. In order to make the domain useful though, we must add at least one DNS server to it.
Adding Reverse DNS Servers This section describes how to add DNS servers to a Reverse DDNS Domain. Repeat them for as many servers as desired for each domain. Reverse DNS Server entries represents a actual DNS servers which support the server side of the DDNS protocol. Each Reverse DNS Server has the following parameters: hostname - The resolvable host name of the DNS server. This value is currently ignored. ip-address - The IP address at which the server listens for DDNS requests. port - The port on which the server listens for DDNS requests. It defaults to the standard DNS service port of 53. To create a new reverse DNS Server, one must first add a new server element to the domain and fill in its parameters. If for example the service is running at "172.88.99.10", then set it as follows: "DhcpDdns": { "reverse-ddns": { "ddns-domains": [ { "name": "1.0.0.0.8.B.D.0.1.0.0.2.ip6.arpa.", "key-name": "", "dns-servers": [ { "hostname": "", "ip-address": "172.88.99.10", "port": 53 } ] } ] } } As stated earlier, "hostname" is not yet supported so, the parameter "ip-address" must be set to the address of the DNS server.
Example DHCP-DDNS Server Configuration This section provides an example DHCP-DDNS server configuration based on a small example network. Let's suppose our example network has three domains, each with their own subnet. Our example network Domain Subnet Forward DNS Servers Reverse DNS Servers four.example.com 192.0.2.0/24 172.16.1.5, 172.16.2.5 172.16.1.5, 172.16.2.5 six.example.com 2001:db8:1::/64 3001:1::50 3001:1::51 example.com 192.0.0.0/16 172.16.2.5 172.16.2.5
We need to construct three forward DDNS Domains: Forward DDNS Domains Needed # DDNS Domain Name DNS Servers 1. four.example.com. 172.16.1.5, 172.16.2.5 2. six.example.com. 3001:1::50 3. example.com. 172.16.2.5
As discussed earlier, FQDN to domain matching is based on the longest match. The FQDN, "myhost.four.example.com.", will match the first domain ("four.example.com") while "admin.example.com." will match the third domain ("example.com"). The FQDN, "other.example.net." will fail to match any domain and would be rejected.
The following example configuration specified the Forward DDNS Domains. "DhcpDdns": { "forward-ddns": { "ddns-domains": [ { "name": "four.example.com.", "key-name": "", "dns-servers": [ { "ip-address": "172.16.1.5" }, { "ip-address": "172.16.2.5" } ] }, { "name": "six.example.com.", "key-name": "", "dns-servers": [ { "ip-address": "2001:db8::1" } ] }, { "name": "example.com.", "key-name": "", "dns-servers": [ { "ip-address": "172.16.2.5" } ] }, ] } } Similarly, we need to construct the three reverse DDNS Domains: Reverse DDNS Domains Needed # DDNS Domain Name DNS Servers 1. 2.0.192.in-addr.arpa. 172.16.1.5, 172.16.2.5 2. 1.0.0.0.8.d.b.0.1.0.0.2.ip6.arpa. 3001:1::50 3. 0.182.in-addr.arpa. 172.16.2.5
An address of "192.0.2.150" will match the first domain, "2001:db8:1::10" will match the second domain, and "192.0.50.77" the third domain.
These Reverse DDNS Domains are specified as follows: "DhcpDdns": { "reverse-ddns": { "ddns-domains": [ { "name": "2.0.192.in-addr.arpa.", "key-name": "", "dns-servers": [ { "ip-address": "172.16.1.5" }, { "ip-address": "172.16.2.5" } ] } { "name": "1.0.0.0.8.B.D.0.1.0.0.2.ip6.arpa.", "key-name": "", "dns-servers": [ { "ip-address": "2001:db8::1" } ] } { "name": "0.192.in-addr.arpa.", "key-name": "", "dns-servers": [ { "ip-address": "172.16.2.5" } ] } ] } }
DHCP-DDNS Server Limitations The following are the current limitations of the DHCP-DDNS Server. Requests received from the DHCP servers are placed in a queue until they are processed. Currently all queued requests are lost when the server shuts down.
kea-1.1.0/doc/guide/keactrl.xml0000664000175000017500000003065012772445242013222 00000000000000 ]> Managing Kea with keactrl
Overview keactrl is a shell script which controls the startup, shutdown and reconfiguration of the Kea servers (kea-dhcp4, kea-dhcp6 and kea-dhcp-ddns). It also provides the means for checking the current status of the servers and determining the configuration files in use.
Command Line Options keactrl is run as follows: keactrl <command> [-c keactrl-config-file] [-s server[,server,..]] <command> is the one of the commands described in . The optional -c keactrl-config-file switch allows specification of an alternate keactrl configuration file. (--ctrl-config is a synonym for -c.) In the absence of -c, keactrl will use the default configuration file [kea-install-dir]/etc/kea/keactrl.conf. The optional -s server[,server ...] switch selects the servers to which the command is issued. (--server is a synonym for -s.) If absent, the command is sent to all servers enabled in the keactrl configuration file. If multiple servers are specified, they should be separated by commas with no intervening spaces.
The keactrl Configuration File Depending on requirements, not all of the available servers need be run. The keactrl configuration file sets which servers are enabled and which are disabled. The default configuration file is [kea-install-dir]/etc/kea/keactrl.conf, but this can be overridden on a per-command basis using the -c switch. The contents of keactrl.conf are: # This is a configuration file for keactrl script which controls # the startup, shutdown, reconfiguration and gathering the status # of the Kea servers. # prefix holds the location where the Kea is installed. prefix=/usr/local # Location of Kea configuration file. kea_config_file=${prefix}/etc/kea/kea.conf # Location of Kea binaries. exec_prefix=${prefix} dhcp4_srv=${exec_prefix}/sbin/kea/kea-dhcp4 dhcp6_srv=${exec_prefix}/sbin/kea/kea-dhcp6 dhcp_ddns_srv=${exec_prefix}/sbin/kea/kea-dhcp-ddns # Start DHCPv4 server? dhcp4=yes # Start DHCPv6 server? dhcp6=yes # Start DHCP DDNS server? dhcp_ddns=yes # Be verbose? kea_verbose=no The dhcp4, dhcp6 and dhcp_ddns parameters set to "yes" configure keactrl to manage (start, reconfigure) all servers, i.e. kea-dhcp4, kea-dhcp6 and kea-dhcp-ddns. When any of these parameters is set to "no" the keactrl will ignore the corresponding server when starting or reconfiguring Kea. By default, Kea servers managed by keactrl are located in [kea-install-dir]/sbin. This should work for most installations. If the default location needs to be altered for any reason, the paths specified with the dhcp4_srv, dhcp6_srv and dhcp_ddns_srv parameters should be modified. The kea_verbose parameter specifies the verbosity of the servers being started. When kea_verbose is set to "yes" the logging level of the server is set to DEBUG. Modification of the logging severity in a configuration file, as described in , will have no effect as long as the kea_verbose is set to "yes". Setting it to "no" will cause the server to use the logging levels specified in the Kea configuration file for respective loggers. If no logging configuration is specified, the default settings will be used. The verbosity for the server is set when it is started. Once started, the verbosity can be only changed by stopping the server and starting it again with the new value of the kea_verbose parameter.
Commands The following commands are supported by keactrl: start - starts selected servers. stop - stops all running servers. reload - triggers reconfiguration of the selected servers by sending the SIGHUP signal to them. status - returns the status of the servers (active or inactive) and the names of the configuration files in use. Typical output from keactrl when starting the servers looks similar to the following: $ keactrl start INFO/keactrl: Starting kea-dhcp4 -c /usr/local/etc/kea/kea.conf -d INFO/keactrl: Starting kea-dhcp6 -c /usr/local/etc/kea/kea.conf -d INFO/keactrl: Starting kea-dhcp-ddns -c /usr/local/etc/kea/kea.conf -d Kea's servers create PID files upon startup. These files are used by keactrl to determine whether or not a given server is running. If one or more servers are running when the start command is issued, the output will look similar to the following: $ keactrl start INFO/keactrl: kea-dhcp4 appears to be running, see: PID 10918, PID file: /usr/local/var/kea/kea.kea-dhcp4.pid. INFO/keactrl: kea-dhcp6 appears to be running, see: PID 10924, PID file: /usr/local/var/kea/kea.kea-dhcp6.pid. INFO/keactrl: kea-dhcp-ddns appears to be running, see: PID 10930, PID file: /usr/local/var/kea/kea.kea-dhcp-ddns.pid. During normal shutdowns these PID files are deleted. They may, however, be left over as remnants following a system crash. It is possible, though highly unlikely, that upon system restart the PIDs they contain actually refer to processes unrelated to Kea. This condition will cause keactrl to decide that the servers are running, when in fact they are not. In such a case the PID files as listed in the keactrl output must be manually deleted. The following command stops all servers: $ keactrl stop INFO/keactrl: Stopping kea-dhcp4... INFO/keactrl: Stopping kea-dhcp6... INFO/keactrl: Stopping kea-dhcp-ddns... Note that the stop will attempt to stop all servers regardless of whether they are "enabled" in the keactrl.conf. If any of the servers are not running, an informational message is displayed as in the stop command output below. $ keactrl stop INFO/keactrl: kea-dhcp4 isn't running. INFO/keactrl: kea-dhcp6 isn't running. INFO/keactrl: kea-dhcp-ddns isn't running. As already mentioned, the reconfiguration of each Kea server is triggered by the SIGHUP signal. The reload command sends the SIGHUP signal to the servers that are enabled in the keactrl configuration file and are currently running. When a server receives the SIGHUP signal it re-reads its configuration file and, if the new configuration is valid, uses the new configuration. A reload is executed as follows: $ keactrl reload INFO/keactrl: Reloading kea-dhcp4... INFO/keactrl: Reloading kea-dhcp6... INFO/keactrl: Reloading kea-dhcp-ddns... If any of the servers are not running, an informational message is displayed as in the reload command output below. $ keactrl stop INFO/keactrl: kea-dhcp4 isn't running. INFO/keactrl: kea-dhcp6 isn't running. INFO/keactrl: kea-dhcp-ddns isn't running. Currently keactrl does not report configuration failures when the server is started or reconfigured. To check if the server's configuration succeeded the Kea log must be examined for errors. By default, this is written to the syslog file. Sometimes it is useful to check which servers are running. The status reports this, typical output looking like: $ keactrl status DHCPv4 server: active DHCPv6 server: inactive DHCP DDNS: active Kea configuration file: /usr/local/etc/kea/kea.conf keactrl configuration file: /usr/local/etc/kea/keactrl.conf
Overriding the Server Selection The optional -s switch allows the selection of the servers to which keactrl command is issued. For example, the following instructs keactrl to stop the kea-dhcp4 and kea-dhcp6 servers and leave the kea-dhcp-ddns server running: $ keactrl stop -s dhcp4,dhcp6 Similarly, the following will only start the kea-dhcp4 and kea-dhcp-ddns servers and not kea-dhcp6. $ keactrl start -s dhcp4,dhcp_ddns Note that the behavior of the -s switch with the start and reload commands is different to its behavior with the stop command. On start and reload, keactrl will check if the servers given as parameters to the -s switch are enabled in the keactrl configuration file: if not, the server will be ignored. For stop however, this check is not made: the command is applied to all listed servers, regardless of whether they have been enabled in the file. The following keywords can be used with the -s command line option: dhcp4 for kea-dhcp4. dhcp6 for kea-dhcp6. dhcp_ddns for kea-dhcp-ddns. all for all servers (default).
kea-1.1.0/doc/guide/kea-messages.html0000664000175000017500000115737012772742653014326 00000000000000Kea Messages Manual

Kea Messages Manual

This is the messages manual for Kea version 1.1.0.

Abstract

This is the messages manual for Kea version 1.1.0. The most up-to-date version of this document, along with other documents for Kea, can be found at http://kea.isc.org/docs.


Chapter 1. Introduction

This document lists each message that can be logged by the programs in the Kea package. Each entry in this manual is of the form:

IDENTIFICATION message-text

... where "IDENTIFICATION" is the message identification included in each message logged and "message-text" is the accompanying message text. The "message-text" may include placeholders of the form "%1", "%2" etc.; these parameters are replaced by relevant values when the message is logged.

Each entry is also accompanied by a description giving more information about the circumstances that result in the message being logged.

For information on configuring and using Kea logging, refer to the Kea Guide.

Chapter 2. Kea Log Messages

ALLOC Module

ALLOC_ENGINE_LEASE_RECLAIMED successfully reclaimed lease %1

This debug message is logged when the allocation engine successfully reclaims a lease. The lease is now available for assignment.

ALLOC_ENGINE_REMOVAL_NCR_FAILED sending removal name change request failed for lease %1: %2

This error message is logged when sending a removal name change request to DHCP DDNS failed. This name change request is usually generated when the lease reclamation routine acts upon expired leases. If a lease being reclaimed has a corresponding DNS entry it needs to be removed. This message indicates that removal of the DNS entry has failed. Nevertheless the lease will be reclaimed.

ALLOC_ENGINE_V4_ALLOC_ERROR %1: error during attempt to allocate an IPv4 address: %2

An error occurred during an attempt to allocate an IPv4 address, the reason for the failure being contained in the message. The server will return a message to the client refusing a lease. The first argument includes the client identification information.

ALLOC_ENGINE_V4_ALLOC_FAIL %1: failed to allocate an IPv4 address after %2 attempt(s)

The DHCP allocation engine gave up trying to allocate an IPv4 address after the specified number of attempts. This probably means that the address pool from which the allocation is being attempted is either empty, or very nearly empty. As a result, the client will have been refused a lease. The first argument includes the client identification information.

This message may indicate that your address pool is too small for the number of clients you are trying to service and should be expanded. Alternatively, if the you know that the number of concurrently active clients is less than the addresses you have available, you may want to consider reducing the lease lifetime. In this way, addresses allocated to clients that are no longer active on the network will become available sooner.

ALLOC_ENGINE_V4_DECLINED_RECOVERED IPv4 address %1 was recovered after %2 seconds of probation-period

This informational message indicates that the specified address was reported as duplicate (client sent DECLINE) and the server marked this address as unvailable for a period of time. This time now has elapsed and the address has been returned to the available pool. This step concludes decline recovery process.

ALLOC_ENGINE_V4_DISCOVER_ADDRESS_CONFLICT %1: conflicting reservation for address %2 with existing lease %3

This warning message is issued when the DHCP server finds that the address reserved for the client can't be offered because this address is currently allocated to another client. The server will try to allocate a different address to the client to use until the conflict is resolved. The first argument includes the client identification information.

ALLOC_ENGINE_V4_DISCOVER_HR client %1 sending DHCPDISCOVER has reservation for the address %2

This message is issued when the allocation engine determines that the client sending the DHCPDISCOVER has a reservation for the specified address. The allocation engine will try to offer this address to the client.

ALLOC_ENGINE_V4_LEASES_RECLAMATION_COMPLETE reclaimed %1 leases in %2

This debug message is logged when the allocation engine completes reclamation of a set of expired leases. The maximum number of leases to be reclaimed in a single pass of the lease reclamation routine is configurable using 'max-reclaim-leases' parameter. However, the number of reclaimed leases may also be limited by the timeout value, configured with 'max-reclaim-time'. The message includes the number of reclaimed leases and the total time.

ALLOC_ENGINE_V4_LEASES_RECLAMATION_SLOW expired leases still exist after %1 reclamations

This warning message is issued when the server has been unable to reclaim all expired leases in a specified number of consecutive attempts. This indicates that the value of "reclaim-timer-wait-time" may be too high. However, if this is just a short burst of leases' expirations the value does not have to be modified and the server should deal with this in subsequent reclamation attempts. If this is a result of a permanent increase of the server load, the value of "reclaim-timer-wait-time" should be decreased, or the values of "max-reclaim-leases" and "max-reclaim-time" should be increased to allow processing more leases in a single cycle. Alternatively, these values may be set to 0 to remove the limitations on the number of leases and duration. However, this may result in longer periods of server's unresponsiveness to DHCP packets, while it processes the expired leases.

ALLOC_ENGINE_V4_LEASES_RECLAMATION_START starting reclamation of expired leases (limit = %1 leases or %2 milliseconds)

This debug message is issued when the allocation engine starts the reclamation of the expired leases. The maximum number of leases to be reclaimed and the timeout is included in the message. If any of these values is 0, it means "unlimited".

ALLOC_ENGINE_V4_LEASES_RECLAMATION_TIMEOUT timeout of %1 ms reached while reclaiming IPv4 leases

This debug message is issued when the allocation engine hits the timeout for performing reclamation of the expired leases. The reclamation will now be interrupted and all leases which haven't been reclaimed, because of the timeout, will be reclaimed when the next scheduled reclamation is started. The argument is the timeout value expressed in milliseconds.

ALLOC_ENGINE_V4_LEASE_RECLAIM %1: reclaiming expired lease for address %2

This debug message is issued when the server begins reclamation of the expired DHCPv4 lease. The first argument specifies the client identification information. The second argument holds the leased IPv4 address.

ALLOC_ENGINE_V4_LEASE_RECLAMATION_FAILED failed to reclaim the lease %1: %2

This error message is logged when the allocation engine fails to reclaim an expired lease. The reason for the failure is included in the message. The error may be triggered in the lease expiration hook or while performing the operation on the lease database.

ALLOC_ENGINE_V4_NO_MORE_EXPIRED_LEASES all expired leases have been reclaimed

This debug message is issued when the server reclaims all expired DHCPv4 leases in the database.

ALLOC_ENGINE_V4_OFFER_EXISTING_LEASE allocation engine will try to offer existing lease to the client %1

This message is issued when the allocation engine determines that the client has a lease in the lease database, it doesn't have reservation for any other lease, and the leased address is not reserved for any other client. The allocation engine will try to offer the same lease to the client.

ALLOC_ENGINE_V4_OFFER_NEW_LEASE allocation engine will try to offer new lease to the client %1

This message is issued when the allocation engine will try to offer a new lease to the client. This is the case when the client doesn't have any existing lease, it has no reservation or the existing or reserved address is leased to another client. Also, the client didn't specify a hint, or the address in the hint is in use.

ALLOC_ENGINE_V4_OFFER_REQUESTED_LEASE allocation engine will try to offer requested lease %1 to the client %2

This message is issued when the allocation engine will try to offer the lease specified in the hint. This situation may occur when: (a) client doesn't have any reservations, (b) client has reservation but the reserved address is leased to another client.

ALLOC_ENGINE_V4_RECLAIMED_LEASES_DELETE begin deletion of reclaimed leases expired more than %1 seconds ago

This debug message is issued when the allocation engine begins deletion of the reclaimed leases which have expired more than a specified number of seconds ago. This operation is triggered periodically according to the "flush-reclaimed-timer-wait-time" parameter. The "hold-reclaimed-time" parameter defines a number of seconds for which the leases are stored before they are removed.

ALLOC_ENGINE_V4_RECLAIMED_LEASES_DELETE_COMPLETE successfully deleted %1 expired-reclaimed leases

This debug message is issued when the server successfully deletes "expired-reclaimed" leases from the lease database. The number of deleted leases is included in the log message.

ALLOC_ENGINE_V4_RECLAIMED_LEASES_DELETE_FAILED deletion of expired-reclaimed leases failed: %1

This error message is issued when the deletion of "expired-reclaimed" leases from the database failed. The error message is appended to the log message.

ALLOC_ENGINE_V4_REQUEST_ADDRESS_RESERVED %1: requested address %2 is reserved

This message is issued when the allocation engine refused to allocate address requested by the client because this address is reserved for another client. The first argument includes the client identification information.

ALLOC_ENGINE_V4_REQUEST_ALLOC_REQUESTED %1: trying to allocate requested address %2

This message is issued when the allocation engine is trying to allocate (or reuse an expired) address which has been requested by the client. The first argument includes the client identification information.

ALLOC_ENGINE_V4_REQUEST_EXTEND_LEASE %1: extending lifetime of the lease for address %2

This message is issued when the allocation engine determines that the client already has a lease whose lifetime can be extended, and which can be returned to the client. The first argument includes the client identification information.

ALLOC_ENGINE_V4_REQUEST_INVALID client %1 having a reservation for address %2 is requesting invalid address %3

This message is logged when the client, having a reservation for one address, is requesting a different address. The client is only allowed to do this when the reserved address is in use by another client. However, the allocation engine has determined that the reserved address is available and the client should request the reserved address.

ALLOC_ENGINE_V4_REQUEST_IN_USE %1: requested address %2 is in use

This message is issued when the client is requesting or has a reservation for an address which is in use. The first argument includes the client identification information.

ALLOC_ENGINE_V4_REQUEST_OUT_OF_POOL client %1, which doesn't have a reservation, requested address %2 out of the dynamic pool

This message is issued when the client has requested allocation of the address which doesn't belong to any address pool from which addresses are dynamically allocated. The client also doesn't have reservation for this address. This address could only be allocated if the client had reservation for it.

ALLOC_ENGINE_V4_REQUEST_PICK_ADDRESS client %1 hasn't specified an address - picking available address from the pool

This message is logged when the client hasn't specified any preferred address (the client should always do it, but Kea tries to be forgiving). The allocation engine will try to pick an available address from the dynamic pool and allocate it to the client.

ALLOC_ENGINE_V4_REQUEST_REMOVE_LEASE %1: removing previous client's lease %2

This message is logged when the allocation engine removes previous lease for the client because the client has been allocated new one.

ALLOC_ENGINE_V4_REQUEST_USE_HR client %1 hasn't requested specific address, using reserved address %2

This message is issued when the client is not requesting any specific address but the allocation engine has determined that there is a reservation for this client. The allocation engine will try to allocate the reserved address.

ALLOC_ENGINE_V4_REUSE_EXPIRED_LEASE_DATA %1: reusing expired lease, updated lease information: %2

This message is logged when the allocation engine is reusing an existing lease. The details of the updated lease are printed. The first argument includes the client identification information.

ALLOC_ENGINE_V6_ALLOC_ERROR %1: error during attempt to allocate an IPv6 address: %2

An error occurred during an attempt to allocate an IPv6 address, the reason for the failure being contained in the message. The server will return a message to the client refusing a lease. The first argument includes the client identification information.

ALLOC_ENGINE_V6_ALLOC_FAIL %1: failed to allocate an IPv6 address after %2 attempt(s)

The DHCP allocation engine gave up trying to allocate an IPv6 address after the specified number of attempts. This probably means that the address pool from which the allocation is being attempted is either empty, or very nearly empty. As a result, the client will have been refused a lease. The first argument includes the client identification information.

This message may indicate that your address pool is too small for the number of clients you are trying to service and should be expanded. Alternatively, if the you know that the number of concurrently active clients is less than the addresses you have available, you may want to consider reducing the lease lifetime. In this way, addresses allocated to clients that are no longer active on the network will become available sooner.

ALLOC_ENGINE_V6_ALLOC_HR_LEASE_EXISTS %1: lease type %2 for reserved address/prefix %3 already exists

This debug message is issued when the allocation engine determines that the lease for the IPv6 address or prefix has already been allocated for the client and the client can continue using it. The first argument includes the client identification information.

ALLOC_ENGINE_V6_ALLOC_LEASES_HR leases and static reservations found for client %1

This message is logged when the allocation engine is in the process of allocating leases for the client, it found existing leases and static reservations for the client. The allocation engine will verify if existing leases match reservations. Those leases that are reserved for other clients and those that are not reserved for the client will be removed. All leases matching the reservations will be renewed and returned.

ALLOC_ENGINE_V6_ALLOC_LEASES_NO_HR no reservations found but leases exist for client %1

This message is logged when the allocation engine is in the process if allocating leases for the client, there are no static reservations, but lease(s) exist for the client. The allocation engine will remove leases which are reserved for other clients, and return all remaining leases to the client.

ALLOC_ENGINE_V6_ALLOC_NO_LEASES_HR no leases found but reservations exist for client %1

This message is logged when the allocation engine is in the process of allocating leases for the client. It hasn't found any existing leases for this client, but the client appears to have static reservations. The allocation engine will try to allocate the reserved resources for the client.

ALLOC_ENGINE_V6_ALLOC_NO_V6_HR %1: unable to allocate reserved leases - no IPv6 reservations

This message is logged when the allocation engine determines that the client has no IPv6 reservations and thus the allocation engine will have to try to allocate allocating leases from the dynamic pool or stop the allocation process if none can be allocated. The first argument includes the client identification information.

ALLOC_ENGINE_V6_ALLOC_UNRESERVED no static reservations available - trying to dynamically allocate leases for client %1

This debug message is issued when the allocation engine will attempt to allocate leases from the dynamic pools. This may be due to one of (a) there are no reservations for this client, (b) there are reservations for the client but they are not usable because the addresses are in use by another client or (c) we had a reserved lease but that has now been allocated to another client.

ALLOC_ENGINE_V6_DECLINED_RECOVERED IPv6 address %1 was recovered after %2 seconds of probation-period

This informational message indicates that the specified address was reported as duplicate (client sent DECLINE) and the server marked this address as unvailable for a period of time. This time now has elapsed and the address has been returned to the available pool. This step concludes decline recovery process.

ALLOC_ENGINE_V6_EXPIRED_HINT_RESERVED %1: expired lease for the client's hint %2 is reserved for another client

This message is logged when the allocation engine finds that the expired lease for the client's hint can't be reused because it is reserved for another client. The first argument includes the client identification information.

ALLOC_ENGINE_V6_EXTEND_ALLOC_UNRESERVED allocate new (unreserved) leases for the renewing client %1

This debug message is issued when the allocation engine is trying to allocate new leases for the renewing client because it was unable to renew any of the existing client's leases, e.g. because leases are reserved for another client or for any other reason.

ALLOC_ENGINE_V6_EXTEND_ERROR %1: allocation engine experienced error with attempting to extend lease lifetime: %2

This error message indicates that an error was experienced during Renew or Rebind processing. Additional explanation is provided with this message. Depending on its nature, manual intervention may be required to continue processing messages from this particular client; other clients will be unaffected. The first argument includes the client identification information.

ALLOC_ENGINE_V6_EXTEND_LEASE %1: extending lifetime of the lease type %2, address %3

This debug message is issued when the allocation engine is trying to extend lifetime of the lease. The first argument includes the client identification information.

ALLOC_ENGINE_V6_EXTEND_LEASE_DATA %1: detailed information about the lease being extended: %2

This debug message prints detailed information about the lease which lifetime is being extended (renew or rebind). The first argument includes the client identification information.

ALLOC_ENGINE_V6_EXTEND_NEW_LEASE_DATA %1: new lease information for the lease being extended: %2

This debug message prints updated information about the lease to be extended. If the lease update is successful, the information printed by this message will be stored in the database. The first argument includes the client identification information.

ALLOC_ENGINE_V6_HINT_RESERVED %1: lease for the client's hint %2 is reserved for another client

This message is logged when the allocation engine cannot allocate the lease using the client's hint because the lease for this hint is reserved for another client. The first argument includes the client identification information.

ALLOC_ENGINE_V6_HR_ADDR_GRANTED reserved address %1 was assigned to client %2

This informational message signals that the specified client was assigned the address reserved for it.

ALLOC_ENGINE_V6_HR_PREFIX_GRANTED reserved prefix %1/%2 was assigned to client %3

This informational message signals that the specified client was assigned the prefix reserved for it.

ALLOC_ENGINE_V6_LEASES_RECLAMATION_COMPLETE reclaimed %1 leases in %2

This debug message is logged when the allocation engine completes reclamation of a set of expired leases. The maximum number of leases to be reclaimed in a single pass of the lease reclamation routine is configurable using 'max-reclaim-leases' parameter. However, the number of reclaimed leases may also be limited by the timeout value, configured with 'max-reclaim-time'. The message includes the number of reclaimed leases and the total time.

ALLOC_ENGINE_V6_LEASES_RECLAMATION_SLOW expired leases still exist after %1 reclamations

This warning message is issued when the server has been unable to reclaim all expired leases in a specified number of consecutive attempts. This indicates that the value of "reclaim-timer-wait-time" may be too high. However, if this is just a short burst of leases' expirations the value does not have to be modified and the server should deal with this in subsequent reclamation attempts. If this is a result of a permanent increase of the server load, the value of "reclaim-timer-wait-time" should be decreased, or the values of "max-reclaim-leases" and "max-reclaim-time" should be increased to allow processing more leases in a single cycle. Alternatively, these values may be set to 0 to remove the limitations on the number of leases and duration. However, this may result in longer periods of server's unresponsiveness to DHCP packets, while it processes the expired leases.

ALLOC_ENGINE_V6_LEASES_RECLAMATION_START starting reclamation of expired leases (limit = %1 leases or %2 milliseconds)

This debug message is issued when the allocation engine starts the reclamation of the expired leases. The maximum number of leases to be reclaimed and the timeout is included in the message. If any of these values is 0, it means "unlimited".

ALLOC_ENGINE_V6_LEASES_RECLAMATION_TIMEOUT timeout of %1 ms reached while reclaiming IPv6 leases

This debug message is issued when the allocation engine hits the timeout for performing reclamation of the expired leases. The reclamation will now be interrupted and all leases which haven't been reclaimed, because of the timeout, will be reclaimed when the next scheduled reclamation is started. The argument is the timeout value expressed in milliseconds.

ALLOC_ENGINE_V6_LEASE_RECLAIM %1: reclaiming expired lease for prefix %2/%3

This debug message is issued when the server begins reclamation of the expired DHCPv6 lease. The reclaimed lease may either be an address lease or delegated prefix. The first argument provides the client identification information. The other arguments specify the prefix and the prefix length for the lease. The prefix length for address lease is equal to 128.

ALLOC_ENGINE_V6_LEASE_RECLAMATION_FAILED failed to reclaim the lease %1: %2

This error message is logged when the allocation engine fails to reclaim an expired lease. The reason for the failure is included in the message. The error may be triggered in the lease expiration hook or while performing the operation on the lease database.

ALLOC_ENGINE_V6_NO_MORE_EXPIRED_LEASES all expired leases have been reclaimed

This debug message is issued when the server reclaims all expired DHCPv6 leases in the database.

ALLOC_ENGINE_V6_RECLAIMED_LEASES_DELETE begin deletion of reclaimed leases expired more than %1 seconds ago

This debug message is issued when the allocation engine begins deletion of the reclaimed leases which have expired more than a specified number of seconds ago. This operation is triggered periodically according to the "flush-reclaimed-timer-wait-time" parameter. The "hold-reclaimed-time" parameter defines a number of seconds for which the leases are stored before they are removed.

ALLOC_ENGINE_V6_RECLAIMED_LEASES_DELETE_COMPLETE successfully deleted %1 expired-reclaimed leases

This debug message is issued when the server successfully deletes "expired-reclaimed" leases from the lease database. The number of deleted leases is included in the log message.

ALLOC_ENGINE_V6_RECLAIMED_LEASES_DELETE_FAILED deletion of expired-reclaimed leases failed: %1

This error message is issued when the deletion of "expired-reclaimed" leases from the database failed. The error message is appended to the log message.

ALLOC_ENGINE_V6_RENEW_HR allocating leases reserved for the client %1 as a result of Renew

This debug message is issued when the allocation engine tries to allocate reserved leases for the client sending a Renew message. The server will also remove any leases that the client is trying to renew that are not reserved for the client.

ALLOC_ENGINE_V6_RENEW_REMOVE_RESERVED %1: checking if existing client's leases are reserved for another client

This message is logged when the allocation engine finds leases for the client and will check if these leases are reserved for another client. If they are, they will not be renewed for the client requesting their renewal. The first argument includes the client identification information.

ALLOC_ENGINE_V6_RENEW_REMOVE_UNRESERVED dynamically allocating leases for the renewing client %1

This debug message is issued as the allocation engine is trying to dynamically allocate new leases for the renewing client. This is the case when the server couldn't renew any of the existing client's leases, e.g. because leased resources are reserved for another client.

ALLOC_ENGINE_V6_REUSE_EXPIRED_LEASE_DATA %1: reusing expired lease, updated lease information: %2

This message is logged when the allocation engine is reusing an existing lease. The details of the updated lease are printed. The first argument includes the client identification information.

ALLOC_ENGINE_V6_REVOKED_ADDR_LEASE address %1 was revoked from client %2 as it is reserved for client %3

This informational message is an indication that the specified IPv6 address was used by client A but it is now reserved for client B. Client A has been told to stop using it so that it can be leased to client B. This is a normal occurrence during conflict resolution, which can occur in cases such as the system administrator adding a reservation for an address that is currently in use by another client. The server will fully recover from this situation, but clients will change their addresses.

ALLOC_ENGINE_V6_REVOKED_PREFIX_LEASE Prefix %1/%2 was revoked from client %3 as it is reserved for client %4

This informational message is an indication that the specified IPv6 prefix was used by client A but it is now reserved for client B. Client A has been told to stop using it so that it can be leased to client B. This is a normal occurrence during conflict resolution, which can occur in cases such as the system administrator adding a reservation for an address that is currently in use by another client. The server will fully recover from this situation, but clients will change their prefixes.

ASIODNS Module

ASIODNS_FD_ADD_TCP adding a new TCP server by opened fd %1

A debug message informing about installing a file descriptor as a server. The file descriptor number is noted.

ASIODNS_FD_ADD_UDP adding a new UDP server by opened fd %1

A debug message informing about installing a file descriptor as a server. The file descriptor number is noted.

ASIODNS_FETCH_COMPLETED upstream fetch to %1(%2) has now completed

A debug message, this records that the upstream fetch (a query made by the resolver on behalf of its client) to the specified address has completed.

ASIODNS_FETCH_STOPPED upstream fetch to %1(%2) has been stopped

An external component has requested the halting of an upstream fetch. This is an allowed operation, and the message should only appear if debug is enabled.

ASIODNS_OPEN_SOCKET error %1 opening %2 socket to %3(%4)

The asynchronous I/O code encountered an error when trying to open a socket of the specified protocol in order to send a message to the target address. The number of the system error that caused the problem is given in the message.

ASIODNS_READ_DATA error %1 reading %2 data from %3(%4)

The asynchronous I/O code encountered an error when trying to read data from the specified address on the given protocol. The number of the system error that caused the problem is given in the message.

ASIODNS_READ_TIMEOUT receive timeout while waiting for data from %1(%2)

An upstream fetch from the specified address timed out. This may happen for any number of reasons and is most probably a problem at the remote server or a problem on the network. The message will only appear if debug is enabled.

ASIODNS_SEND_DATA error %1 sending data using %2 to %3(%4)

The asynchronous I/O code encountered an error when trying to send data to the specified address on the given protocol. The number of the system error that caused the problem is given in the message.

ASIODNS_SYNC_UDP_CLOSE_FAIL failed to close a DNS/UDP socket: %1

This is the same to ASIODNS_UDP_CLOSE_FAIL but happens on the "synchronous UDP server", mainly used for the authoritative DNS server daemon.

ASIODNS_TCP_ACCEPT_FAIL failed to accept TCP DNS connection: %1

Accepting a TCP connection from a DNS client failed due to an error that could happen but should be rare. The reason for the error is included in the log message. The server still keeps accepting new connections, so unless it happens often it's probably okay to ignore this error. If the shown error indicates something like "too many open files", it's probably because the run time environment is too restrictive on this limitation, so consider adjusting the limit using a tool such as ulimit. If you see other types of errors too often, there may be something overlooked; please file a bug report in that case.

ASIODNS_TCP_CLEANUP_CLOSE_FAIL failed to close a DNS/TCP socket on port cleanup: %1

A TCP DNS server tried to close a TCP socket (one created on accepting a new connection or is already unused) as a step of cleaning up the corresponding listening port, but it failed to do that. This is generally an unexpected event and so is logged as an error. See also the description of ASIODNS_TCP_CLOSE_ACCEPTOR_FAIL.

ASIODNS_TCP_CLOSE_ACCEPTOR_FAIL failed to close listening TCP socket: %1

A TCP DNS server tried to close a listening TCP socket (for accepting new connections) as a step of cleaning up the corresponding listening port (e.g., on server shutdown or updating port configuration), but it failed to do that. This is generally an unexpected event and so is logged as an error. See ASIODNS_TCP_CLOSE_FAIL on the implication of related system resources.

ASIODNS_TCP_CLOSE_FAIL failed to close DNS/TCP socket with a client: %1

A TCP DNS server tried to close a TCP socket used to communicate with a client, but it failed to do that. While closing a socket should normally be an error-free operation, there have been known cases where this happened with a "connection reset by peer" error. This might be because of some odd client behavior, such as sending a TCP RST after establishing the connection and before the server closes the socket, but how exactly this could happen seems to be system dependent (i.e, it's not part of the standard socket API), so it's difficult to provide a general explanation. In any case, it is believed that an error on closing a socket doesn't mean leaking system resources (the kernel should clean up any internal resource related to the socket, just reporting an error detected in the close call), but, again, it seems to be system dependent. This message is logged at a debug level as it's known to happen and could be triggered by a remote node and it would be better to not be too verbose, but you might want to increase the log level and make sure there's no resource leak or other system level troubles when it's logged.

ASIODNS_TCP_CLOSE_NORESP_FAIL failed to close DNS/TCP socket with a client: %1

A TCP DNS server tried to close a TCP socket used to communicate with a client without returning an answer (which normally happens for zone transfer requests), but it failed to do that. See ASIODNS_TCP_CLOSE_FAIL for more details.

ASIODNS_TCP_GETREMOTE_FAIL failed to get remote address of a DNS TCP connection: %1

A TCP DNS server tried to get the address and port of a remote client on a connected socket but failed. It's expected to be rare but can still happen. See also ASIODNS_TCP_READLEN_FAIL.

ASIODNS_TCP_READDATA_FAIL failed to get DNS data on a TCP socket: %1

A TCP DNS server tried to read a DNS message (that follows a 2-byte length field) but failed. It's expected to be rare but can still happen. See also ASIODNS_TCP_READLEN_FAIL.

ASIODNS_TCP_READLEN_FAIL failed to get DNS data length on a TCP socket: %1

A TCP DNS server tried to get the length field of a DNS message (the first 2 bytes of a new chunk of data) but failed. This is generally expected to be rare but can still happen, e.g, due to an unexpected reset of the connection. A specific reason for the failure is included in the log message.

ASIODNS_TCP_WRITE_FAIL failed to send DNS message over a TCP socket: %1

A TCP DNS server tried to send a DNS message to a remote client but failed. It's expected to be rare but can still happen. See also ASIODNS_TCP_READLEN_FAIL.

ASIODNS_UDP_ASYNC_SEND_FAIL Error sending UDP packet to %1: %2

The low-level ASIO library reported an error when trying to send a UDP packet in asynchronous UDP mode. This can be any error reported by send_to(), and can indicate problems such as too high a load on the network, or a problem in the underlying library or system. This packet is dropped and will not be sent, but service should resume normally. If you see a single occurrence of this message, it probably does not indicate any significant problem, but if it is logged often, it is probably a good idea to inspect your network traffic.

ASIODNS_UDP_CLOSE_FAIL failed to close a DNS/UDP socket: %1

A UDP DNS server tried to close its UDP socket, but failed to do that. This is generally an unexpected event and so is logged as an error.

ASIODNS_UDP_RECEIVE_FAIL failed to receive UDP DNS packet: %1

Receiving a UDP packet from a DNS client failed due to an error that could happen but should be very rare. The server still keeps receiving UDP packets on this socket. The reason for the error is included in the log message. This log message is basically not expected to appear at all in practice; if it does, there may be some system level failure and other system logs may have to be checked.

ASIODNS_UDP_SYNC_RECEIVE_FAIL failed to receive UDP DNS packet: %1

This is the same to ASIODNS_UDP_RECEIVE_FAIL but happens on the "synchronous UDP server", mainly used for the authoritative DNS server daemon.

ASIODNS_UDP_SYNC_SEND_FAIL Error sending UDP packet to %1: %2

The low-level ASIO library reported an error when trying to send a UDP packet in synchronous UDP mode. See ASIODNS_UDP_ASYNC_SEND_FAIL for more information.

ASIODNS_UNKNOWN_ORIGIN unknown origin for ASIO error code %1 (protocol: %2, address %3)

An internal consistency check on the origin of a message from the asynchronous I/O module failed. This may indicate an internal error; please submit a bug report.

ASIODNS_UNKNOWN_RESULT unknown result (%1) when IOFetch::stop() was executed for I/O to %2(%3)

An internal error indicating that the termination method of the resolver's upstream fetch class was called with an unknown result code (which is given in the message). Please submit a bug report.

COMMAND Module

COMMAND_DEREGISTERED Command %1 deregistered

This debug message indicates that the daemon stopped supporting specified command. This command can no longer be issued. If the command socket is open and this command is issued, the daemon will not be able to process it.

COMMAND_PROCESS_ERROR1 Error while processing command: %1

This warning message indicates that the server encountered an error while processing received command. Additional information will be provided, if available. Additional log messages may provide more details.

COMMAND_PROCESS_ERROR2 Error while processing command: %1

This warning message indicates that the server encountered an error while processing received command. The difference, compared to COMMAND_PROCESS_ERROR1 is that the initial command was well formed and the error occurred during logic processing, not the command parsing. Additional information will be provided, if available. Additional log messages may provide more details.

COMMAND_RECEIVED Received command '%1'

This informational message indicates that a command was received over command socket. The nature of this command and its possible results will be logged with separate messages.

COMMAND_REGISTERED Command %1 registered

This debug message indicates that the daemon started supporting specified command. If the command socket is open, this command can now be issued.

COMMAND_RESPONSE_ERROR Server failed to generate response for command: %1

This error message indicates that the server failed to generate response for specified command. This likely indicates a server logic error, as the server is expected to generate valid responses for all commands, even malformed ones.

COMMAND_SOCKET_ACCEPT_FAIL Failed to accept incoming connection on command socket %1: %2

This error indicates that the server detected incoming connection and executed accept system call on said socket, but this call returned an error. Additional information may be provided by the system as second parameter.

COMMAND_SOCKET_CONNECTION_CLOSED Closed socket %1 for existing command connection

This is an informational message that the socket created for handling client's connection is closed. This usually means that the client disconnected, but may also mean a timeout.

COMMAND_SOCKET_CONNECTION_OPENED Opened socket %1 for incoming command connection on socket %2

This is an informational message that a new incoming command connection was detected and a dedicated socket was opened for that connection.

COMMAND_SOCKET_FAIL_NONBLOCK Failed to set non-blocking mode for socket %1 created for incoming connection on socket %2: %3

This error message indicates that the server failed to set non-blocking mode on just created socket. That socket was created for accepting specific incoming connection. Additional information may be provided as third parameter.

COMMAND_SOCKET_READ Received %1 bytes over command socket %2

This debug message indicates that specified number of bytes was received over command socket identified by specified file descriptor.

COMMAND_SOCKET_READ_FAIL Encountered error %1 while reading from command socket %2

This error message indicates that an error was encountered while reading from command socket.

COMMAND_SOCKET_RESPONSE_TOOLARGE Server's response was larger (%1) than supported 64KB

This error message indicates that the server received a command and generated an answer for it, but that response was larger than supported 64KB. Server will attempt to send the first 64KB of the response. Depending on the nature of this response, this may indicate a software or configuration error. Future Kea versions are expected to have better support for large responses.

COMMAND_SOCKET_UNIX_CLOSE Command socket closed: UNIX, fd=%1, path=%2

This informational message indicates that the daemon closed a command processing socket. This was a UNIX socket. It was opened with the file descriptor and path specified.

COMMAND_SOCKET_UNIX_OPEN Command socket opened: UNIX, fd=%1, path=%2

This informational message indicates that the daemon opened a command processing socket. This is a UNIX socket. It was opened with the file descriptor and path specified.

COMMAND_SOCKET_WRITE Sent response of %1 bytes over command socket %2

This debug message indicates that the specified number of bytes was sent over command socket identifier by the specified file descriptor.

COMMAND_SOCKET_WRITE_FAIL Error while writing %1 bytes to command socket %2

This error message indicates that an error was encountered while attempting to send a response to the command socket.

DCTL Module

DCTL_CCSESSION_ENDING %1 ending control channel session

This debug message is issued just before the controller attempts to disconnect from its session with the Kea control channel.

DCTL_CCSESSION_STARTING %1 starting control channel session, specfile: %2

This debug message is issued just before the controller attempts to establish a session with the Kea control channel.

DCTL_COMMAND_RECEIVED %1 received command: %2, arguments: %3

A debug message listing the command (and possible arguments) received from the Kea control system by the controller.

DCTL_CONFIG_COMPLETE server has completed configuration: %1

This is an informational message announcing the successful processing of a new configuration. It is output during server startup, and when an updated configuration is committed by the administrator. Additional information may be provided.

DCTL_CONFIG_FILE_LOAD_FAIL %1 reason: %2

This fatal error message indicates that the application attempted to load its initial configuration from file and has failed. The service will exit.

DCTL_CONFIG_LOAD_FAIL %1 configuration failed to load: %2

This critical error message indicates that the initial application configuration has failed. The service will start, but will not process requests until the configuration has been corrected.

DCTL_CONFIG_START parsing new configuration: %1

A debug message indicating that the application process has received an updated configuration and has passed it to its configuration manager for parsing.

DCTL_CONFIG_STUB %1 configuration stub handler called

This debug message is issued when the dummy handler for configuration events is called. This only happens during initial startup.

DCTL_CONFIG_UPDATE %1 updated configuration received: %2

A debug message indicating that the controller has received an updated configuration from the Kea configuration system.

DCTL_INIT_PROCESS %1 initializing the application

This debug message is issued just before the controller attempts to create and initialize its application instance.

DCTL_INIT_PROCESS_FAIL %1 application initialization failed: %2

This error message is issued if the controller could not initialize the application and will exit.

DCTL_NOT_RUNNING %1 application instance is not running

A warning message is issued when an attempt is made to shut down the application when it is not running.

DCTL_PARSER_FAIL : %1

On receipt of a new configuration, the server failed to create a parser to decode the contents of the named configuration element, or the creation succeeded but the parsing actions and committal of changes failed. The reason for the failure is given in the message.

DCTL_PROCESS_FAILED %1 application execution failed: %2

The controller has encountered a fatal error while running the application and is terminating. The reason for the failure is included in the message.

DCTL_RUN_PROCESS %1 starting application event loop

This debug message is issued just before the controller invokes the application run method.

DCTL_SESSION_FAIL %1 controller failed to establish Kea session: %1

The controller has failed to establish communication with the rest of Kea and will exit.

DCTL_STANDALONE %1 skipping message queue, running standalone

This is a debug message indicating that the controller is running in the application in standalone mode. This means it will not connected to the Kea message queue. Standalone mode is only useful during program development, and should not be used in a production environment.

DHCP4 Module

DHCP4_ACTIVATE_INTERFACE activating interface %1

This message is printed when DHCPv4 server enabled an interface to be used to receive DHCPv4 traffic. IPv4 socket on this interface will be opened once Interface Manager starts up procedure of opening sockets.

DHCP4_ALREADY_RUNNING %1 already running? %2

This is an error message that occurs when the DHCPv4 server encounters a pre-existing PID file which contains the PID of a running process. This most likely indicates an attempt to start a second instance of the server using the same configuration file. It is possible, though unlikely that the PID file is a remnant left behind by a server crash or power failure and the PID it contains refers to a process other than the server. In such an event, it would be necessary to manually remove the PID file. The first argument is the DHCPv4 process name, the second contains the PID and PID file.

DHCP4_BUFFER_RECEIVED received buffer from %1:%2 to %3:%4 over interface %5

This debug message is logged when the server has received a packet over the socket. When the message is logged the contents of the received packet hasn't been parsed yet. The only available information is the interface and the source and destination IPv4 addresses/ports.

DHCP4_BUFFER_RECEIVE_FAIL error on attempt to receive packet: %1

The DHCPv4 server tried to receive a packet but an error occurred during this attempt. The reason for the error is included in the message.

DHCP4_BUFFER_UNPACK parsing buffer received from %1 to %2 over interface %3

This debug message is issued when the server starts parsing the received buffer holding the DHCPv4 message. The arguments specify the source and destination IPv4 addresses as well as the interface over which the buffer has been received.

DHCP4_BUFFER_WAIT waiting for next DHCPv4 packet with timeout %1 ms

This debug message is issued when the server enters the state when it waits for new packets. The argument specifies the timeout for the server to wait for the packet. When this time elapses the server will pass through its main loop to perform handling of any pending signals and timers. After that, it will enter the wait state again.

DHCP4_BUFFER_WAIT_INTERRUPTED interrupted wait for the next packet due to timeout, signal or external socket callback (timeout value is %1)

This debug message is issued when the server interrupts waiting for reception of the next DHCPv6 message due to timeout, signal or reception of the data over socket other than used for DHCPv4 message transmission. The server will now handle signals received and ready timers before waiting for next packets again. The argument specifies the timeout value in milliseconds.

DHCP4_BUFFER_WAIT_SIGNAL signal received while waiting for next packet, next waiting signal is %1

This debug message is issued when the server was waiting for the packet, but the wait has been interrupted by the signal received by the process. The signal will be handled before the server starts waiting for next packets. The argument specifies the next signal to be handled by the server.

DHCP4_CCSESSION_STARTED control channel session started on socket %1

A debug message issued during startup after the DHCPv4 server has successfully established a session with the Kea control channel.

DHCP4_CCSESSION_STARTING starting control channel session, specfile: %1

This debug message is issued just before the DHCPv4 server attempts to establish a session with the Kea control channel.

DHCP4_CLASS_ASSIGNED %1: client packet has been assigned to the following class(es): %2

This debug message informs that incoming packet has been assigned to specified class or classes. This is a normal behavior and indicates successful operation. The first argument specifies the client and transaction identification information. The second argument includes all classes to which the packet has been assigned.

DHCP4_CLASS_UNCONFIGURED %1: client packet belongs to an unconfigured class: %2

This debug message informs that incoming packet belongs to a class which cannot be found in the configuration. Either a hook written before the classification was added to Kea is used, or class naming is inconsistent.

DHCP4_CLIENTID_IGNORED_FOR_LEASES %1: not using client identifier for lease allocation for subnet %2

This debug message is issued when the server is processing the DHCPv4 message for which client identifier will not be used when allocating new lease or renewing existing lease. The server is explicitly configured to not use client identifier to lookup existing leases for the client and will not record client identifier in the lease database. This mode of operation is useful when clients don't use stable client identifiers, e.g. multi stage booting. Note that the client identifier may be used for other operations than lease allocation, e.g. identifying host reservations for the client using client identifier. The first argument includes the client and transaction identification information. The second argument specifies the identifier of the subnet where the client is connected and for which this mode of operation is configured on the server.

DHCP4_CLIENT_FQDN_DATA %1: Client sent FQDN option: %2

This debug message includes the detailed information extracted from the Client FQDN option sent in the query. The first argument includes the client and transaction identification information. The second argument specifies the detailed information about the FQDN option received by the server.

DHCP4_CLIENT_FQDN_PROCESS %1: processing Client FQDN option

This debug message is issued when the server starts processing the Client FQDN option sent in the client's query. The argument includes the client and transaction identification information.

DHCP4_CLIENT_HOSTNAME_DATA %1: client sent Hostname option: %2

This debug message includes the detailed information extracted from the Hostname option sent in the query. The first argument includes the client and transaction identification information. The second argument specifies the hostname carried in the Hostname option sent by the client.

DHCP4_CLIENT_HOSTNAME_PROCESS %1: processing client's Hostname option

This debug message is issued when the server starts processing the Hostname option sent in the client's query. The argument includes the client and transaction identification information.

DHCP4_CLIENT_NAME_PROC_FAIL %1: failed to process the fqdn or hostname sent by a client: %2

This debug message is issued when the DHCP server was unable to process the FQDN or Hostname option sent by a client. This is likely because the client's name was malformed or due to internal server error. The first argument contains the client and transaction identification information. The second argument holds the detailed description of the error.

DHCP4_COMMAND_RECEIVED received command %1, arguments: %2

A debug message listing the command (and possible arguments) received from the Kea control system by the DHCPv4 server.

DHCP4_CONFIG_COMPLETE DHCPv4 server has completed configuration: %1

This is an informational message announcing the successful processing of a new configuration. It is output during server startup, and when an updated configuration is committed by the administrator. Additional information may be provided.

DHCP4_CONFIG_LOAD_FAIL configuration error using file: %1, reason: %2

This error message indicates that the DHCPv4 configuration has failed. If this is an initial configuration (during server's startup) the server will fail to start. If this is a dynamic reconfiguration attempt the server will continue to use an old configuration.

DHCP4_CONFIG_NEW_SUBNET a new subnet has been added to configuration: %1

This is an informational message reporting that the configuration has been extended to include the specified IPv4 subnet.

DHCP4_CONFIG_OPTION_DUPLICATE multiple options with the code %1 added to the subnet %2

This warning message is issued on an attempt to configure multiple options with the same option code for a particular subnet. Adding multiple options is uncommon for DHCPv4, but is not prohibited.

DHCP4_CONFIG_RECEIVED received configuration %1

A debug message listing the configuration received by the DHCPv4 server. The source of that configuration depends on used configuration backend.

DHCP4_CONFIG_START DHCPv4 server is processing the following configuration: %1

This is a debug message that is issued every time the server receives a configuration. That happens at start up and also when a server configuration change is committed by the administrator.

DHCP4_CONFIG_UPDATE updated configuration received: %1

A debug message indicating that the DHCPv4 server has received an updated configuration from the Kea configuration system.

DHCP4_DDNS_REQUEST_SEND_FAILED failed sending a request to kea-dhcp-ddns, error: %1, ncr: %2

This error message indicates that DHCP4 server attempted to send a DDNS update request to the DHCP-DDNS server. This is most likely a configuration or networking error.

DHCP4_DEACTIVATE_INTERFACE deactivate interface %1

This message is printed when DHCPv4 server disables an interface from being used to receive DHCPv4 traffic. Sockets on this interface will not be opened by the Interface Manager until interface is enabled.

DHCP4_DECLINE_LEASE Received DHCPDECLINE for addr %1 from client %2. The lease will be unavailable for %3 seconds.

This informational message is printed when a client received an address, but discovered that it is being used by some other device and notified the server by sending a DHCPDECLINE message. The server checked that this address really was leased to the client and marked this address as unusable for a certain amount of time. This message may indicate a misconfiguration in a network, as there is either a buggy client or more likely a device that is using an address that it is not supposed to. The server will fully recover from this situation, but if the underlying problem of a misconfigured or rogue device is not solved, this address may be declined again in the future.

DHCP4_DECLINE_LEASE_MISMATCH Received DHCPDECLINE for addr %1 from client %2, but the data doesn't match: received hwaddr: %3, lease hwaddr: %4, received client-id: %5, lease client-id: %6

This informational message means that a client attempted to report his address as declined (i.e. used by unknown entity). The server has information about a lease for that address, but the client's hardware address or client identifier does not match the server's stored information. The client's request will be ignored.

DHCP4_DECLINE_LEASE_NOT_FOUND Received DHCPDECLINE for addr %1 from client %2, but no such lease found.

This warning message indicates that a client reported that his address was detected as a duplicate (i.e. another device in the network is using this address). However, the server does not have a record for this address. This may indicate a client's error or a server's purged database.

DHCP4_DHCP4O6_BAD_PACKET received malformed DHCPv4o6 packet: %1

A malformed DHCPv4o6 packet was received.

DHCP4_DHCP4O6_PACKET_SEND %1: trying to send packet %2 (type %3) to %4 on interface %5 encapsulating %6: %7 (type %8)

The arguments specify the client identification information (HW address and client identifier), DHCPv6 message name and type, source IPv6 address and interface name, DHCPv4 client identification, message name and type.

DHCP4_DHCP4O6_PACKET_SEND_FAIL %1: failed to send DHCPv4o6 packet: %2

This error is output if the IPv4 DHCP server fails to send an DHCPv4o6 message to the IPv6 DHCP server. The reason for the error is included in the message.

DHCP4_DHCP4O6_RECEIVE_FAIL failed to receive DHCPv4o6: %1

This debug message indicates the inter-process communication with the DHCPv6 server failed. The reason for the error is included in the message.

DHCP4_DHCP4O6_RECEIVING receiving DHCPv4o6 packet from DHCPv6 server

This debug message is printed when the server is receiving a DHCPv4o6 from the DHCPv6 server over inter-process communication socket.

DHCP4_DHCP4O6_RESPONSE_DATA %1: responding with packet %2 (type %3), packet details: %4

A debug message including the detailed data about the packet being sent to the DHCPv6 server to be forwarded to the client. The first argument contains the client and the transaction identification information. The second and third argument contains the packet name and type respectively. The fourth argument contains detailed packet information.

DHCP4_DYNAMIC_RECONFIGURATION initiate server reconfiguration using file: %1, after receiving SIGHUP signal

This is the info message logged when the DHCPv4 server starts reconfiguration as a result of receiving SIGHUP signal.

DHCP4_DYNAMIC_RECONFIGURATION_FAIL dynamic server reconfiguration failed with file: %1

This is an error message logged when the dynamic reconfiguration of the DHCP server failed.

DHCP4_EMPTY_HOSTNAME %1: received empty hostname from the client, skipping processing of this option

This debug message is issued when the server received an empty Hostname option from a client. Server does not process empty Hostname options and therefore option is skipped. The argument holds the client and transaction identification information.

DHCP4_GENERATE_FQDN %1: client did not send a FQDN or hostname; FQDN will be be generated for the client

This debug message is issued when the server did not receive a Hostname option from the client and hostname generation is enabled. This provides a means to create DNS entries for unsophisticated clients.

DHCP4_HANDLE_SIGNAL_EXCEPTION An exception was thrown while handing signal: %1

This error message is printed when an ISC or standard exception was raised during signal processing. This likely indicates a coding error and should be reported to ISC.

DHCP4_HOOKS_LIBS_RELOAD_FAIL reload of hooks libraries failed

A "libreload" command was issued to reload the hooks libraries but for some reason the reload failed. Other error messages issued from the hooks framework will indicate the nature of the problem.

DHCP4_HOOK_BUFFER_RCVD_SKIP received buffer from %1 to %2 over interface %3 was dropped because a callout set the skip flag

This debug message is printed when a callout installed on buffer4_receive hook point set the skip flag. For this particular hook point, the setting of the flag by a callout instructs the server to drop the packet. The arguments specify the source and destination IPv4 address as well as the name of the interface over which the buffer has been received.

DHCP4_HOOK_BUFFER_SEND_SKIP %1: prepared response is dropped because a callout set the skip flag.

This debug message is printed when a callout installed on buffer4_send hook point set the skip flag. For this particular hook point, the setting of the flag by a callout instructs the server to drop the packet. Server completed all the processing (e.g. may have assigned, updated or released leases), but the response will not be send to the client.

DHCP4_HOOK_DECLINE_SKIP Decline4 hook callouts set status to DROP, ignoring packet.

This message indicates that the server received DHCPDECLINE message, it was verified to be correct and matching server's lease information. The server called hooks for decline4 hook point and one of the callouts set next step status to DROP. The server will now abort processing of the packet as if it was never received. The lease will continue to be assigned to this client.

DHCP4_HOOK_LEASE4_RELEASE_SKIP %1: lease was not released because a callout set the skip flag.

This debug message is printed when a callout installed on lease4_release hook point set the skip flag. For this particular hook point, the setting of the flag by a callout instructs the server to not release a lease.

DHCP4_HOOK_PACKET_RCVD_SKIP %1: packet is dropped, because a callout set the skip flag.

This debug message is printed when a callout installed on the pkt4_receive hook point sets the skip flag. For this particular hook point, the setting of the flag instructs the server to drop the packet.

DHCP4_HOOK_PACKET_SEND_SKIP %1: prepared response is not sent, because a callout set skip flag.

This debug message is printed when a callout installed on the pkt4_send hook point sets the skip flag. For this particular hook point, the setting of the flag instructs the server to drop the packet. This means that the client will not get any response, even though the server processed client's request and acted on it (e.g. possibly allocated a lease).

DHCP4_HOOK_SUBNET4_SELECT_SKIP %1: no subnet was selected, because a callout set skip flag.

This debug message is printed when a callout installed on the subnet4_select hook point sets the skip flag. For this particular hook point, the setting of the flag instructs the server not to choose a subnet, an action that severely limits further processing; the server will be only able to offer global options - no addresses will be assigned. The argument specifies the client and transaction identification information.

DHCP4_INFORM_DIRECT_REPLY %1: DHCPACK in reply to the DHCPINFORM will be sent directly to %2 over %3

This debug message is issued when the DHCPACK will be sent directly to the client, rather than via a relay. The first argument contains the client and transaction identification information. The second argument contains the client's IPv4 address to which the response will be sent. The third argument contains the local interface name.

DHCP4_INIT_FAIL failed to initialize Kea server: %1

The server has failed to initialize. This may be because the configuration was not successful, or it encountered any other critical error on startup. Attached error message provides more details about the issue.

DHCP4_INIT_REBOOT %1: client is in INIT-REBOOT state and requests address %2

This informational message is issued when the client is in the INIT-REBOOT state and is requesting an IPv4 address it is using to be allocated for it. The first argument includes the client and transaction identification information. The second argument specifies the requested IPv4 address.

DHCP4_LEASE_ADVERT %1: lease %2 will be advertised

This informational message indicates that the server has found the lease to be offered to the client. It is up to the client to choose one server out of those which offered leases and continue allocation with that server. The first argument specifies the client and the transaction identification information. The second argument specifies the IPv4 address to be offered.

DHCP4_LEASE_ALLOC %1: lease %2 has been allocated

This informational message indicates that the server successfully granted a lease in response to client's DHCPREQUEST message. The lease information will be sent to the client in the DHCPACK message. The first argument contains the client and the transaction identification information. The second argument contains the allocated IPv4 address.

DHCP4_NAME_GEN_UPDATE_FAIL %1: failed to update the lease after generating name %2 for a client: %3

This message indicates the failure when trying to update the lease and/or options in the server's response with the hostname generated by the server from the acquired IPv4 address. The message argument indicates the reason for the failure. The first argument includes the client and the transaction identification information. The second argument specifies the hostname. The third argument contains the error details.

DHCP4_NCR_CREATE %1: DDNS updates enabled, therefore sending name change requests

This debug message is issued when the server is starting to send name change requests to the D2 module to update records for the client in the DNS. This includes removal of old records and addition of the new records as required. Details of the name change requests will be logged in additional log entries. The argument includes the client and the transaction identification information.

DHCP4_NCR_CREATION_FAILED %1: failed to generate name change requests for DNS: %2

This message indicates that server was unable to generate NameChangeRequests which should be sent to the kea-dhcp_ddns module to create new DNS records for the lease being acquired or to update existing records for the renewed lease. The first argument contains the client and transaction identification information. The second argument includes the reason for the failure.

DHCP4_NOT_RUNNING DHCPv4 server is not running

A warning message is issued when an attempt is made to shut down the DHCPv4 server but it is not running.

DHCP4_NO_LEASE_INIT_REBOOT %1: no lease for address %2 requested by INIT-REBOOT client

This debug message is issued when the client being in the INIT-REBOOT state requested an IPv4 address but this client is unknown. The server will not respond. The first argument includes the client and the transaction id identification information. The second argument includes the IPv4 address requested by the client.

DHCP4_NO_SOCKETS_OPEN no interface configured to listen to DHCP traffic

This warning message is issued when current server configuration specifies no interfaces that server should listen on, or specified interfaces are not configured to receive the traffic.

DHCP4_OPEN_SOCKET opening sockets on port %1

A debug message issued during startup, this indicates that the DHCPv4 server is about to open sockets on the specified port.

DHCP4_OPEN_SOCKET_FAIL failed to open socket: %1

A warning message issued when IfaceMgr fails to open and bind a socket. The reason for the failure is appended as an argument of the log message.

DHCP4_PACKET_DROP_0001 failed to parse packet from %1 to %2, received over interace %3, reason: %4

The DHCPv4 server has received a packet that it is unable to interpret. The reason why the packet is invalid is included in the message.

DHCP4_PACKET_DROP_0002 %1, from interface %2: no suitable subnet configured for a direct client

This info message is logged when received a message from a directly connected client but there is no suitable subnet configured for the interface on which this message has been received. The IPv4 address assigned on this interface must belong to one of the configured subnets. Otherwise received message is dropped.

DHCP4_PACKET_DROP_0003 %1, from interface %2: it contains a foreign server identifier

This debug message is issued when received DHCPv4 message is dropped because it is addressed to a different server, i.e. a server identifier held by this message doesn't match the identifier used by our server. The arguments of this message hold the name of the transaction id and interface on which the message has been received.

DHCP4_PACKET_DROP_0004 %1, from interface %2: missing msg-type option

This is a debug message informing that incoming DHCPv4 packet did not have mandatory DHCP message type option and thus was dropped. The arguments specify the client and transaction identification information, as well as the interface on which the message has been received.

DHCP4_PACKET_DROP_0005 %1: unrecognized type %2 in option 53

This debug message indicates that the message type carried in DHCPv4 option 53 is unrecognized by the server. The valid message types are listed on the IANA website: http://www.iana.org/assignments/bootp-dhcp-parameters/bootp-dhcp-parameters.xhtml#message-type-53. The message will not be processed by the server. The arguments specify the client and transaction identification information, as well as the received message type.

DHCP4_PACKET_DROP_0006 %1: unsupported DHCPv4 message type %2

This debug message indicates that the message type carried in DHCPv4 option 53 is valid but the message will not be processed by the server. This includes messages being normally sent by the server to the client, such as DHCPOFFER, DHCPACK, DHCPNAK etc. The first argument specifies the client and transaction identification information. The second argument specifies the message type.

DHCP4_PACKET_DROP_0007 %1: failed to process packet: %2

This is a general catch-all message indicating that the processing of a received packet failed. The reason is given in the message. The server will not send a response but will instead ignore the packet. The first argument contains the client and transaction identification information. The second argument includes the details of the error.

DHCP4_PACKET_NAK_0001 %1: failed to select a subnet for incoming packet, src %2, type %3

This error message is output when a packet was received from a subnet for which the DHCPv4 server has not been configured. The most probable cause is a misconfiguration of the server. The first argument contains the client and transaction identification information. The second argument contains the source IPv4 address of the packet. The third argument contains the name of the received packet.

DHCP4_PACKET_NAK_0002 %1: invalid address %2 requested by INIT-REBOOT

This debug message is issued when the client being in the INIT-REBOOT state requested an IPv4 address which is not assigned to him. The server will respond to this client with DHCPNAK. The first argument contains the client and the transaction identification information. The second arguments holds the IPv4 address requested by the client.

DHCP4_PACKET_NAK_0003 %1: failed to advertise a lease, client sent ciaddr %2, requested-ip-address %3

This message indicates that the server has failed to offer a lease to the specified client after receiving a DISCOVER message from it. There are many possible reasons for such a failure. The first argument contains the client and the transaction identification information. The second argument contains the IPv4 address in the ciaddr field. The third argument contains the IPv4 address in the requested-ip-address option (if present).

DHCP4_PACKET_NAK_0004 %1: failed to grant a lease, client sent ciaddr %2, requested-ip-address %3

This message indicates that the server failed to grant a lease to the specified client after receiving a REQUEST message from it. There are many possible reasons for such a failure. Additional messages will indicate the reason. The first argument contains the client and the transaction identification information. The second argument contains the IPv4 address in the ciaddr field. The third argument contains the IPv4 address in the requested-ip-address option (if present).

DHCP4_PACKET_PACK %1: preparing on-wire format of the packet to be sent

This debug message is issued when the server starts preparing the on-wire format of the packet to be sent back to the client. The argument specifies the client and the transaction identification information.

DHCP4_PACKET_PACK_FAIL %1: preparing on-wire-format of the packet to be sent failed %2

This error message is issued when preparing an on-wire format of the packet has failed. The first argument identifies the client and the DHCP transaction. The second argument includes the error string.

DHCP4_PACKET_PROCESS_EXCEPTION exception occurred during packet processing

This error message indicates that a non-standard exception was raised during packet processing that was not caught by other, more specific exception handlers. This packet will be dropped and the server will continue operation.

DHCP4_PACKET_PROCESS_STD_EXCEPTION exception occurred during packet processing: %1

This error message indicates that a standard exception was raised during packet processing that was not caught by other, more specific exception handlers. This packet will be dropped and the server will continue operation.

DHCP4_PACKET_RECEIVED %1: %2 (type %3) received from %4 to %5 on interface %6

A debug message noting that the server has received the specified type of packet on the specified interface. The first argument specifies the client and transaction identification information. The second and third argument specify the name of the DHCPv4 message and its numeric type respectively. The remaining arguments specify the source IPv4 address, destination IPv4 address and the name of the interface on which the message has been received.

DHCP4_PACKET_SEND %1: trying to send packet %2 (type %3) from %4:%5 to %6:%7 on interface %8

The arguments specify the client identification information (HW address and client identifier), DHCP message name and type, source IPv4 address and port, destination IPv4 address and port and the interface name.

This debug message is issued when the server is trying to send the response to the client. When the server is using an UDP socket to send the packet there are cases when this operation may be unsuccessful and no error message will be displayed. One such situation occurs when the server is unicasting the response to the 'ciaddr' of a DHCPINFORM message. This often requires broadcasting an ARP message to obtain the link layer address of the unicast destination. If broadcast ARP messages are blocked in the network, according to the firewall policy, the ARP message will not cause a response. Consequently, the response to the DHCPINFORM will not be sent. Since the ARP communication is under the OS control, Kea is not notified about the drop of the packet which it is trying to send and it has no means to display an error message.

DHCP4_PACKET_SEND_FAIL %1: failed to send DHCPv4 packet: %2

This error is output if the DHCPv4 server fails to send an assembled DHCP message to a client. The first argument includes the client and the transaction identification information. The second argument includes the reason for failure.

DHCP4_PARSER_COMMIT_EXCEPTION parser failed to commit changes

On receipt of message containing details to a change of the DHCPv4 server configuration, a set of parsers were successfully created, but one of them failed to commit its changes due to a low-level system exception being raised. Additional messages may be output indicating the reason.

DHCP4_PARSER_COMMIT_FAIL parser failed to commit changes: %1

On receipt of message containing details to a change of the DHCPv4 server configuration, a set of parsers were successfully created, but one of them failed to commit its changes. The reason for the failure is given in the message.

DHCP4_PARSER_CREATED created parser for configuration element %1

A debug message output during a configuration update of the DHCPv4 server, notifying that the parser for the specified configuration element has been successfully created.

DHCP4_PARSER_EXCEPTION failed to create or run parser for configuration element %1

On receipt of message containing details to a change of its configuration, the DHCPv4 server failed to create a parser to decode the contents of the named configuration element, or the creation succeeded but the parsing actions and committal of changes failed. The message has been output in response to a non-Kea exception being raised. Additional messages may give further information.

DHCP4_PARSER_FAIL failed to create or run parser for configuration element %1: %2

On receipt of message containing details to a change of its configuration, the DHCPv4 server failed to create a parser to decode the contents of the named configuration element, or the creation succeeded but the parsing actions and committal of changes failed. The reason for the failure is given in the message.

DHCP4_QUERY_DATA %1, packet details: %2

A debug message printing the details of the received packet. The first argument includes the client and the transaction identification information.

DHCP4_RELEASE %1: address %2 was released properly.

This informational message indicates that an address was released properly. It is a normal operation during client shutdown. The first argument includes the client and transaction identification information. The second argument includes the released IPv4 address.

DHCP4_RELEASE_EXCEPTION %1: while trying to release address %2 an exception occurred: %3

This message is output when an error was encountered during an attempt to process a DHCPRELEASE message. The error will not affect the client, which does not expect any response from the server for DHCPRELEASE messages. Depending on the nature of problem, it may affect future server operation. The first argument includes the client and the transaction identification information. The second argument includes the IPv4 address which release was attempted. The last argument includes the detailed error description.

DHCP4_RELEASE_FAIL %1: failed to remove lease for address %2

This error message indicates that the software failed to remove a lease from the lease database. It is probably due to an error during a database operation: resolution will most likely require administrator intervention (e.g. check if DHCP process has sufficient privileges to update the database). It may also be triggered if a lease was manually removed from the database during RELEASE message processing. The first argument includes the client and the transaction identification information. The second argument holds the IPv4 address which release was attempted.

DHCP4_RELEASE_FAIL_NO_LEASE %1: client is trying to release non-existing lease %2

This debug message is printed when client attempts to release a lease, but no such lease is known to the server. The first argument contains the client and transaction identification information. The second argument contains the IPv4 address which the client is trying to release.

DHCP4_RELEASE_FAIL_WRONG_CLIENT %1: client is trying to release the lease %2 which belongs to a different client

This debug message is issued when a client is trying to release the lease for the address which is currently used by another client, i.e. the 'client identifier' or 'chaddr' doesn't match between the client and the lease. The first argument includes the client and the transaction identification information. The second argument specifies the leased address.

DHCP4_RESERVED_HOSTNAME_ASSIGNED %1: server assigned reserved hostname %2

This debug message is issued when the server found a hostname reservation for a client and uses this reservation in a hostname option sent back to this client. The reserved hostname is qualified with a value of 'qualifying-suffix' parameter, if this parameter is specified.

DHCP4_RESPONSE_DATA %1: responding with packet %2 (type %3), packet details: %4

A debug message including the detailed data about the packet being sent to the client. The first argument contains the client and the transaction identification information. The second and third argument contains the packet name and type respectively. The fourth argument contains detailed packet information.

DHCP4_RESPONSE_FQDN_DATA %1: including FQDN option in the server's response: %2

This debug message is issued when the server is adding the Client FQDN option in its response to the client. The first argument includes the client and transaction identification information. The second argument includes the details of the FQDN option being included. Note that the name carried in the FQDN option may be modified by the server when the lease is acquired for the client.

DHCP4_RESPONSE_HOSTNAME_DATA %1: including Hostname option in the server's response: %2

This debug message is issued when the server is adding the Hostname option in its response to the client. The first argument includes the client and transaction identification information. The second argument includes the details of the FQDN option being included. Note that the name carried in the Hostname option may be modified by the server when the lease is acquired for the client.

DHCP4_RESPONSE_HOSTNAME_GENERATE %1: server has generated hostname %2 for the client

This debug message includes the auto-generated hostname which will be used for the client which message is processed. Hostnames may need to be generated when required by the server's configuration or when the client hasn't supplied its hostname. The first argument includes the client and the transaction identification information. The second argument holds the generated hostname.

DHCP4_SERVER_FAILED server failed: %1

The DHCPv4 server has encountered a fatal error and is terminating. The reason for the failure is included in the message.

DHCP4_SHUTDOWN server shutdown

The DHCPv4 server has terminated normally.

DHCP4_SHUTDOWN_REQUEST shutdown of server requested

This debug message indicates that a shutdown of the DHCPv4 server has been requested via a call to the 'shutdown' method of the core Dhcpv4Srv object.

DHCP4_SRV_CONSTRUCT_ERROR error creating Dhcpv4Srv object, reason: %1

This error message indicates that during startup, the construction of a core component within the DHCPv4 server (the Dhcpv4 server object) has failed. As a result, the server will exit. The reason for the failure is given within the message.

DHCP4_SRV_D2STOP_ERROR error stopping IO with DHCP_DDNS during shutdown: %1

This error message indicates that during shutdown, an error occurred while stopping IO between the DHCPv4 server and the DHCP_DDNS server. This is probably due to a programmatic error is not likely to impact either server upon restart. The reason for the failure is given within the message.

DHCP4_SRV_DHCP4O6_ERROR error stopping IO with DHCPv4o6 during shutdown: %1

This error message indicates that during shutdown, an error occurred while stopping IO between the DHCPv4 server and the DHCPv6o6 server. This is probably due to a programmatic error is not likely to impact either server upon restart. The reason for the failure is given within the message.

DHCP4_STARTED Kea DHCPv4 server version %1 started

This informational message indicates that the DHCPv4 server has processed all configuration information and is ready to process DHCPv4 packets. The version is also printed.

DHCP4_STARTING Kea DHCPv4 server version %1 starting

This informational message indicates that the DHCPv4 server has processed any command-line switches and is starting. The version is also printed.

DHCP4_START_INFO pid: %1, port: %2, verbose: %3

This is a debug message issued during the DHCPv4 server startup. It lists some information about the parameters with which the server is running.

DHCP4_SUBNET_DATA %1: the selected subnet details: %2

This debug message includes the details of the subnet selected for the client. The first argument includes the client and the transaction identification information. The second arguments includes the subnet details.

DHCP4_SUBNET_SELECTED %1: the subnet with ID %2 was selected for client assignments

This is a debug message noting the selection of a subnet to be used for address and option assignment. Subnet selection is one of the early steps in the processing of incoming client message. The first argument includes the client and the transaction identification information. The second argument holds the selected subnet id.

DHCP4_SUBNET_SELECTION_FAILED %1: failed to select subnet for the client

This debug message indicates that the server failed to select the subnet for the client which has sent a message to the server. The server will not be able to offer any lease to the client and will drop its message if the received message was DHCPDISCOVER, and will send DHCPNAK if the received message was DHCPREQUEST. The argument includes the client and the transaction identification information.

DHCP6 Module

DHCP6_ACTIVATE_INTERFACE activating interface %1

This message is printed when DHCPv6 server enabled an interface to be used to receive DHCPv6 traffic. IPv6 socket on this interface will be opened once Interface Manager starts up procedure of opening sockets.

DHCP6_ADD_GLOBAL_STATUS_CODE %1: adding Status Code to DHCPv6 packet: %2

This message is logged when the server is adding the top-level Status Code option. The first argument includes the client and the transaction identification information. The second argument includes the details of the status code.

DHCP6_ADD_STATUS_CODE_FOR_IA %1: adding Status Code to IA with iaid=%2: %3

This message is logged when the server is adding the Status Code option to an IA. The first argument includes the client and the transaction identification information. The second argument specifies the IAID. The third argument includes the details of the status code.

DHCP6_ALREADY_RUNNING %1 already running? %2

This is an error message that occurs when the DHCPv6 server encounters a pre-existing PID file which contains the PID of a running process. This most likely indicates an attempt to start a second instance of the server using the same configuration file. It is possible, though unlikely that the PID file is a remnant left behind by a server crash or power failure and the PID it contains refers to a process other than the server. In such an event, it would be necessary to manually remove the PID file. The first argument is the DHCPv6 process name, the second contains the PID and PID file.

DHCP6_BUFFER_RECEIVED received buffer from %1:%2 to %3:%4 over interface %5

This debug message is logged when the server has received a packet over the socket. When the message is logged the contents of the received packet hasn't been parsed yet. The only available information is the interface and the source and destination addresses/ports.

DHCP6_BUFFER_UNPACK parsing buffer received from %1 to %2 over interface %3

This debug message is issued when the server starts parsing the received buffer holding the DHCPv6 message. The arguments specify the source and destination addresses as well as the interface over which the buffer has been received.

DHCP6_BUFFER_WAIT waiting for next DHCPv6 packet with timeout %1 ms

This debug message is issued when the server enters the state when it waits for new packets. The argument specifies the timeout for the server to wait for the packet. When this time elapses the server will pass through its main loop to perform handling of any pending signals and timers. After that, it will enter the wait state again.

DHCP6_BUFFER_WAIT_INTERRUPTED interrupted wait for the next packet due to timeout, signal or external socket callback (timeout value is %1)

This debug message is issued when the server interrupts waiting for reception of the next DHCPv6 message due to timeout, signal or reception of the data over socket other than used for DHCPv6 message transmission. The server will now handle signals received and ready timers before waiting for next packets again. The argument specifies the timeout value in milliseconds.

DHCP6_BUFFER_WAIT_SIGNAL signal received while waiting for next packet, next waiting signal is %1

This debug message is issued when the server was waiting for the packet, but the wait has been interrupted by the signal received by the process. The signal will be handled before the server starts waiting for next packets. The argument specifies the next signal to be handled by the server.

DHCP6_CCSESSION_STARTED control channel session started on socket %1

A debug message issued during startup after the IPv6 DHCP server has successfully established a session with the Kea control channel.

DHCP6_CCSESSION_STARTING starting control channel session, specfile: %1

This debug message is issued just before the IPv6 DHCP server attempts to establish a session with the Kea control channel.

DHCP6_CLASS_ASSIGNED %1: client packet has been assigned to the following class(es): %2

This debug message informs that incoming packet has been assigned to specified class or classes. This is a normal behavior and indicates successful operation. The first argument specifies the client and transaction identification information. The second argument includes all classes to which the packet has been assigned.

DHCP6_CLASS_UNCONFIGURED %1: client packet belongs to an unconfigured class: %1

This debug message informs that incoming packet belongs to a class which cannot be found in the configuration. Either a hook written before the classification was added to Kea is used, or class naming is inconsistent.

DHCP6_COMMAND_RECEIVED received command %1, arguments: %2

A debug message listing the command (and possible arguments) received from the Kea control system by the IPv6 DHCP server.

DHCP6_CONFIG_COMPLETE DHCPv6 server has completed configuration: %1

This is an informational message announcing the successful processing of a new configuration. it is output during server startup, and when an updated configuration is committed by the administrator. Additional information may be provided.

DHCP6_CONFIG_LOAD_FAIL configuration error using file: %1, reason: %2

This error message indicates that the DHCPv6 configuration has failed. If this is an initial configuration (during server's startup) the server will fail to start. If this is a dynamic reconfiguration attempt the server will continue to use an old configuration.

DHCP6_CONFIG_NEW_SUBNET a new subnet has been added to configuration: %1

This is an informational message reporting that the configuration has been extended to include the specified subnet.

DHCP6_CONFIG_OPTION_DUPLICATE multiple options with the code: %1 added to the subnet: %2

This warning message is issued on an attempt to configure multiple options with the same option code for the particular subnet. Adding multiple options is uncommon for DHCPv6, but it is not prohibited.

DHCP6_CONFIG_RECEIVED received configuration: %1

A debug message listing the configuration received by the DHCPv6 server. The source of that configuration depends on used configuration backend.

DHCP6_CONFIG_START DHCPv6 server is processing the following configuration: %1

This is a debug message that is issued every time the server receives a configuration. That happens start up and also when a server configuration change is committed by the administrator.

DHCP6_CONFIG_UPDATE updated configuration received: %1

A debug message indicating that the IPv6 DHCP server has received an updated configuration from the Kea configuration system.

DHCP6_DB_BACKEND_STARTED lease database started (type: %1, name: %2)

This informational message is printed every time the IPv6 DHCP server is started. It indicates what database backend type is being to store lease and other information.

DHCP6_DDNS_CREATE_ADD_NAME_CHANGE_REQUEST created name change request: %1

This debug message is logged when the new Name Change Request has been created to perform the DNS Update, which adds new RRs.

DHCP6_DDNS_FQDN_GENERATED %1: generated FQDN for the client: %2

This debug message is logged when the server generated FQDN (name) for the client which message is processed. The names may be generated by the server when required by the server's policy or when the client doesn't provide any specific FQDN in its message to the server. The first argument includes the client and transaction identification information. The second argument includes the generated FQDN.

DHCP6_DDNS_GENERATED_FQDN_UPDATE_FAIL %1: failed to update the lease using address %2, after generating FQDN for a client, reason: %3

This message indicates the failure when trying to update the lease and/or options in the server's response with the hostname generated by the server from the acquired address. The first argument includes the client and the transaction identification information. The second argument is a leased address. The third argument includes the reason for the failure.

DHCP6_DDNS_GENERATE_FQDN %1: client did not send a FQDN option; FQDN will be

generated for the client. This debug message is issued when the server did not receive a FQDN option from the client and client name replacement is enabled. This provides a means to create DNS entries for unsophisticated clients.

DHCP6_DDNS_LEASE_RENEW_FQDN_CHANGE FQDN %1: FQDN for the renewed lease: %2 has changed. New values: hostname = %3, reverse mapping = %4, forward mapping = %5

This debug message is logged when FQDN mapping for a particular lease has been changed by the recent Renew message. This mapping will be changed in DNS. The first argument includes the client and the transaction identification information. The second argument holds the details about the lease for which the FQDN information and/or mappings have changed. The remaining arguments hold the new FQDN information and flags for mappings.

DHCP6_DDNS_RECEIVE_FQDN %1: received DHCPv6 Client FQDN option: %2

This debug message is logged when server has found the DHCPv6 Client FQDN Option sent by a client and started processing it. The first argument includes the client and transaction identification information. The second argument includes the received FQDN.

DHCP6_DDNS_REQUEST_SEND_FAILED failed sending a request to kea-dhcp-ddns, error: %1, ncr: %2

This error message indicates that IPv6 DHCP server failed to send a DDNS update request to the DHCP-DDNS server. This is most likely a configuration or networking error.

DHCP6_DDNS_RESPONSE_FQDN_DATA %1: including FQDN option in the server's response: %2

This debug message is issued when the server is adding the Client FQDN option in its response to the client. The first argument includes the client and transaction identification information. The second argument includes the details of the FQDN option being included. Note that the name carried in the FQDN option may be modified by the server when the lease is acquired for the client.

DHCP6_DDNS_SEND_FQDN sending DHCPv6 Client FQDN Option to the client: %1

This debug message is logged when server includes an DHCPv6 Client FQDN Option in its response to the client.

DHCP6_DEACTIVATE_INTERFACE deactivate interface %1

This message is printed when DHCPv6 server disables an interface from being used to receive DHCPv6 traffic. Sockets on this interface will not be opened by the Interface Manager until interface is enabled.

DHCP6_DECLINE_FAIL_DUID_MISMATCH Client %1 sent DECLINE for address %2, but it belongs to client with DUID %3

This informational message is printed when a client attempts to decline a lease, but that lease belongs to a different client. The decline request will be rejected.

DHCP6_DECLINE_FAIL_IAID_MISMATCH Client %1 sent DECLINE for address %2, but used a wrong IAID (%3), instead of expected %4

This informational message is printed when a client attempts to decline a lease. The server has a lease for this address, it belongs to this client, but the recorded IAID does not match what client has sent. This means the server will reject this Decline.

DHCP6_DECLINE_FAIL_LEASE_WITHOUT_DUID Client %1 sent DECLINE for address %2, but the associated lease has no DUID

This error condition likely indicates database corruption, as every IPv6 lease is supposed to have a DUID, even if it is an empty one.

DHCP6_DECLINE_FAIL_NO_LEASE Client %1 sent DECLINE for address %2, but there's no lease for it

This informational message is printed when a client tried to decline an address, but the server has no lease for said address. This means that the server's and client's perception of the leases are different. The likely causes of this could be: a confused (e.g. skewed clock) or broken client (e.g. client moved to a different location and didn't notice) or possibly an attack (a rogue client is trying to decline random addresses). The server will inform the client that his decline request was rejected and client should be able to recover from that.

DHCP6_DECLINE_LEASE Client %1 sent DECLINE for address %2 and the server marked it as declined. The lease will be recovered in %3 seconds.

This informational message indicates that the client leased an address, but discovered that it is being used by some other device and reported this to the server by sending a Decline message. The server marked the lease as declined. This likely indicates a misconfiguration in the network. Either the server is configured with an incorrect pool or there are devices that have statically assigned addresses that are supposed to be assigned by the DHCP server. Both client (will request a different address) and server (will recover the lease after decline-probation-time elapses) will recover automatically. However, if the underlying problem is not solved, the conditions leading to this message may reappear.

DHCP6_DECLINE_PROCESS_IA Processing of IA (IAID: %1) from client %2 started.

This debug message is printed when the server starts processing an IA_NA option received in Decline message. It's expected that the option will contain an address that is being declined. Specific information will be printed in a separate message.

DHCP6_DHCP4O6_PACKET_RECEIVED received DHCPv4o6 packet from DHCPv6 server (type %1) for %2 on interface %3

This debug message is printed when the server is receiving a DHCPv4o6 from the DHCPv6 server over inter-process communication.

DHCP6_DHCP4O6_PACKET_RECEIVED (1) received DHCPv4o6 packet from DHCPv4 server (type %1) for %2 on interface %3

This debug message is printed when the server is receiving a DHCPv4o6 from the DHCPv4 server over inter-process communication.

DHCP6_DHCP4O6_RECEIVE_FAIL failed to receive DHCPv4o6: %1

This debug message indicates the inter-process communication with the DHCPv4 server failed. The reason for the error is included in the message.

DHCP6_DHCP4O6_RECEIVING receiving DHCPv4o6 packet from DHCPv4 server

This debug message is printed when the server is receiving a DHCPv4o6 from the DHCPv4 server over inter-process communication socket.

DHCP6_DHCP4O6_SEND_FAIL failed to send DHCPv4o6 packet: %1

This error is output if the IPv6 DHCP server fails to send an assembled DHCPv4o6 message to a client. The reason for the error is included in the message.

DHCP6_DYNAMIC_RECONFIGURATION initiate server reconfiguration using file: %1, after receiving SIGHUP signal

This is the info message logged when the DHCPv6 server starts reconfiguration as a result of receiving SIGHUP signal.

DHCP6_DYNAMIC_RECONFIGURATION_FAIL dynamic server reconfiguration failed with file: %1

This is an error message logged when the dynamic reconfiguration of the DHCP server failed.

DHCP6_HANDLE_SIGNAL_EXCEPTION An exception was thrown while handing signal: %1

This error message is printed when an exception was raised during signal processing. This likely indicates a coding error and should be reported to ISC.

DHCP6_HOOKS_LIBS_RELOAD_FAIL reload of hooks libraries failed

A "libreload" command was issued to reload the hooks libraries but for some reason the reload failed. Other error messages issued from the hooks framework will indicate the nature of the problem.

DHCP6_HOOK_BUFFER_RCVD_SKIP received buffer from %1 to %2 over interface %3 was dropped because a callout set the skip flag

This debug message is printed when a callout installed on buffer6_receive hook point set the skip flag. For this particular hook point, the setting of the flag by a callout instructs the server to drop the packet. The arguments specify the source and destination address as well as the name of the interface over which the buffer has been received.

DHCP6_HOOK_BUFFER_SEND_SKIP %1: prepared DHCPv6 response was dropped because a callout set the skip flag

This debug message is printed when a callout installed on buffer6_send hook point set the skip flag. For this particular hook point, the setting of the flag by a callout instructs the server to drop the packet. Server completed all the processing (e.g. may have assigned, updated or released leases), but the response will not be send to the client. The argument includes the client and transaction identification information.

DHCP6_HOOK_DECLINE_DROP During Decline processing (client=%1, interface=%2, addr=%3) hook callout set status to DROP, dropping packet.

This message indicates that the server received DECLINE message, it was verified to be correct and matching server's lease information. The server called hooks for the lease6_decline hook point and one of the callouts set next step status to DROP. The server will now abort processing of the packet as if it was never received. The lease will continue to be assigned to this client.

DHCP6_HOOK_DECLINE_SKIP During Decline processing (client=%1, interface=%2, addr=%3) hook callout set status to SKIP, skipping decline.

This message indicates that the server received DECLINE message, it was verified to be correct and matching server's lease information. The server called hooks for the lease6_decline hook point and one of the callouts set next step status to SKIP. The server will skip the operation of moving the lease to the declined state and will continue processing the packet. In particular, it will send a REPLY message as if the decline actually took place.

DHCP6_HOOK_LEASE6_RELEASE_NA_SKIP %1: DHCPv6 address lease was not released because a callout set the skip flag

This debug message is printed when a callout installed on the lease6_release hook point set the skip flag. For this particular hook point, the setting of the flag by a callout instructs the server to not release a lease. If a client requested the release of multiples leases (by sending multiple IA options), the server will retain this particular lease and proceed with other releases as usual. The argument holds the client and transaction identification information.

DHCP6_HOOK_LEASE6_RELEASE_PD_SKIP %1: prefix lease was not released because a callout set the skip flag

This debug message is printed when a callout installed on lease6_release hook point set the skip flag. For this particular hook point, the setting of the flag by a callout instructs the server to not release a lease. If client requested release of multiples leases (by sending multiple IA options), the server will retains this particular lease and will proceed with other renewals as usual. The argument holds the client and transaction identification information.

DHCP6_HOOK_PACKET_RCVD_SKIP %1: packet is dropped, because a callout set the skip flag.

This debug message is printed when a callout installed on the pkt6_receive hook point sets the skip flag. For this particular hook point, the setting of the flag instructs the server to drop the packet.

DHCP6_HOOK_PACKET_SEND_SKIP %1: prepared DHCPv6 response was not sent because a callout set the skip flag

This debug message is printed when a callout installed on the pkt6_send hook point set the skip flag. For this particular hook point, the setting of the flag by a callout instructs the server to drop the packet. This effectively means that the client will not get any response, even though the server processed client's request and acted on it (e.g. possibly allocated a lease). The argument specifies the client and transaction identification information.

DHCP6_HOOK_SUBNET6_SELECT_SKIP %1: no subnet was selected because a callout set the skip flag

This debug message is printed when a callout installed on the subnet6_select hook point set the skip flag. For this particular hook point, the setting of the flag instructs the server not to choose a subnet, an action that severely limits further processing; the server will be only able to offer global options - no addresses or prefixes will be assigned. The argument holds the client and transaction identification information.

DHCP6_INIT_FAIL failed to initialize Kea server: %1

The server has failed to establish communication with the rest of Kea, failed to read JSON configuration file or encountered any other critical issue that prevents it from starting up properly. Attached error message provides more details about the issue.

DHCP6_LEASE_ADVERT %1: lease for address %2 and iaid=%3 will be advertised

This informational message indicates that the server will advertise an address to the client in the ADVERTISE message. The client will request allocation of this address with the REQUEST message sent in the next message exchange. The first argument includes the client and transaction identification information. The remaining arguments hold the allocated address and IAID.

DHCP6_LEASE_ADVERT_FAIL %1: failed to advertise an address lease for iaid=%2

This message indicates that in response to a received SOLICIT, the server failed to advertise a non-temporary lease for a given client. There may be many reasons for such failure. Each failure is logged in a separate log entry. The first argument holds the client and transaction identification information. The second argument holds the IAID.

DHCP6_LEASE_ALLOC %1: lease for address %2 and iaid=%3 has been allocated

This informational message indicates that in response to a client's REQUEST message, the server successfully granted a non-temporary address lease. This is a normal behavior and indicates successful operation. The first argument includes the client and transaction identification information. The remaining arguments hold the allocated address and IAID.

DHCP6_LEASE_ALLOC_FAIL %1: failed to grant an address lease for iaid=%2

This message indicates that in response to a received REQUEST, the server failed to grant a non-temporary address lease for the client. There may be many reasons for such failure. Each failure is logged in a separate log entry. The first argument holds the client and transaction identification information. The second argument holds the IAID.

DHCP6_LEASE_DATA %1: detailed lease information for iaid=%2: %3

This debug message is used to print the detailed information about the allocated lease or a lease which will be advertised to the client. The first argument holds the client and the transaction identification information. The second argument holds the IAID. The third argument holds the detailed lease information.

DHCP6_LEASE_NA_WITHOUT_DUID %1: address lease for address %2 does not have a DUID

This error message indicates a database consistency problem. The lease database has an entry indicating that the given address is in use, but the lease does not contain any client identification. This is most likely due to a software error: please raise a bug report. As a temporary workaround, manually remove the lease entry from the database. The first argument includes the client and transaction identification information. The second argument holds the address to be released.

DHCP6_LEASE_PD_WITHOUT_DUID %1: lease for prefix %2/%3 does not have a DUID

This error message indicates a database consistency failure. The lease database has an entry indicating that the given prefix is in use, but the lease does not contain any client identification. This is most likely due to a software error: please raise a bug report. As a temporary workaround, manually remove the lease entry from the database. The first argument includes client and transaction identification information. The second and third argument hold the prefix and the prefix length.

DHCP6_LEASE_RENEW %1: lease for address %2 and iaid=%3 has been allocated

This informational message indicates that in response to a client's REQUEST message, the server successfully renewed a non-temporary address lease. This is a normal behavior and indicates successful operation. The first argument includes the client and transaction identification information. The remaining arguments hold the allocated address and IAID.

DHCP6_NOT_RUNNING IPv6 DHCP server is not running

A warning message is issued when an attempt is made to shut down the IPv6 DHCP server but it is not running.

DHCP6_NO_INTERFACES failed to detect any network interfaces

During startup the IPv6 DHCP server failed to detect any network interfaces and is therefore shutting down.

DHCP6_NO_SOCKETS_OPEN no interface configured to listen to DHCP traffic

This warning message is issued when current server configuration specifies no interfaces that server should listen on, or specified interfaces are not configured to receive the traffic.

DHCP6_OPEN_SOCKET opening sockets on port %1

A debug message issued during startup, this indicates that the IPv6 DHCP server is about to open sockets on the specified port.

DHCP6_OPEN_SOCKET_FAIL failed to open socket: %1

A warning message issued when IfaceMgr fails to open and bind a socket. The reason for the failure is appended as an argument of the log message.

DHCP6_PACKET_DROP_PARSE_FAIL failed to parse packet from %1 to %2, received over interface %3, reason: %4

The DHCPv4 server has received a packet that it is unable to interpret. The reason why the packet is invalid is included in the message.

DHCP6_PACKET_DROP_SERVERID_MISMATCH %1: dropping packet with server identifier: %2, server is using: %3

A debug message noting that server has received message with server identifier option that not matching server identifier that server is using.

DHCP6_PACKET_DROP_UNICAST %1: dropping unicast %2 packet as this packet should be sent to multicast

This debug message is issued when the server drops the unicast packet, because packets of this type must be sent to multicast. The first argument specifies the client and transaction identification information, the second argument specifies packet type.

DHCP6_PACKET_PROCESS_EXCEPTION exception occurred during packet processing

This error message indicates that a non-standard exception was raised during packet processing that was not caught by other, more specific exception handlers. This packet will be dropped and the server will continue operation.

DHCP6_PACKET_PROCESS_FAIL processing of %1 message received from %2 failed: %3

This is a general catch-all message indicating that the processing of the specified packet type from the indicated address failed. The reason is given in the message. The server will not send a response but will instead ignore the packet.

DHCP6_PACKET_PROCESS_STD_EXCEPTION exception occurred during packet processing: %1

This error message indicates that a standard exception was raised during packet processing that was not caught by other, more specific exception handlers. This packet will be dropped and the server will continue operation.

DHCP6_PACKET_RECEIVED %1: %2 (type %3) received from %4 to %5 on interface %6

A debug message noting that the server has received the specified type of packet on the specified interface. The first argument specifies the client and transaction identification information. The second and third argument specify the name of the DHCPv6 message and its numeric type respectively. The remaining arguments specify the source address, destination IP address and the name of the interface on which the message has been received.

DHCP6_PACKET_RECEIVE_FAIL error on attempt to receive packet: %1

The IPv6 DHCP server tried to receive a packet but an error occurred during this attempt. The reason for the error is included in the message.

DHCP6_PACKET_SEND_FAIL failed to send DHCPv6 packet: %1

This error is output if the IPv6 DHCP server fails to send an assembled DHCP message to a client. The reason for the error is included in the message.

DHCP6_PACK_FAIL failed to assemble response correctly

This error is output if the server failed to assemble the data to be returned to the client into a valid packet. The reason is most likely to be to a programming error: please raise a bug report.

DHCP6_PARSER_COMMIT_EXCEPTION parser failed to commit changes

On receipt of message containing details to a change of the IPv6 DHCP server configuration, a set of parsers were successfully created, but one of them failed to commit its changes due to a low-level system exception being raised. Additional messages may be output indicating the reason.

DHCP6_PARSER_COMMIT_FAIL parser failed to commit changes: %1

On receipt of message containing details to a change of the IPv6 DHCP server configuration, a set of parsers were successfully created, but one of them failed to commit its changes. The reason for the failure is given in the message.

DHCP6_PARSER_CREATED created parser for configuration element %1

A debug message output during a configuration update of the IPv6 DHCP server, notifying that the parser for the specified configuration element has been successfully created.

DHCP6_PARSER_EXCEPTION failed to create or run parser for configuration element %1

On receipt of message containing details to a change of its configuration, the IPv6 DHCP server failed to create a parser to decode the contents of the named configuration element, or the creation succeeded but the parsing actions and committal of changes failed. The message has been output in response to a non-Kea exception being raised. Additional messages may give further information.

The most likely cause of this is that the specification file for the server (which details the allowable contents of the configuration) is not correct for this version of Kea. This may be the result of an interrupted installation of an update to Kea.

DHCP6_PARSER_FAIL failed to create or run parser for configuration element %1: %2

On receipt of message containing details to a change of its configuration, the IPv6 DHCP server failed to create a parser to decode the contents of the named configuration element, or the creation succeeded but the parsing actions and committal of changes failed. The reason for the failure is given in the message.

DHCP6_PD_LEASE_ADVERT %1: lease for prefix %2/%3 and iaid=%4 will be advertised

This informational message indicates that the server will advertise a prefix to the client in the ADVERTISE message. The client will request allocation of this prefix with the REQUEST message sent in the next message exchange. The first argument includes the client and transaction identification information. The remaining arguments hold the allocated prefix, prefix length and IAID.

DHCP6_PD_LEASE_ADVERT_FAIL %1: failed to advertise a prefix lease for iaid=%2

This message indicates that in response to a received SOLICIT, the server failed to advertise a prefix lease for a given client. There may be many reasons for such failure. Each failure is logged in a separate log entry. The first argument holds the client and transaction identification information. The second argument holds the IAID.

DHCP6_PD_LEASE_ALLOC %1: lease for prefix %2/%3 and iaid=%4 has been allocated

This informational message indicates that in response to a client's REQUEST message, the server successfully granted a prefix lease. This is a normal behavior and indicates successful operation. The first argument includes the client and transaction identification information. The remaining arguments hold the allocated prefix, prefix length and and IAID.

DHCP6_PD_LEASE_ALLOC_FAIL %1: failed to grant a prefix lease for iaid=%2

This message indicates that in response to a received REQUEST, the server failed to grant a prefix lease for the client. There may be many reasons for such failure. Each failure is logged in a separate log entry. The first argument holds the client and transaction identification information. The second argument holds the IAID.

DHCP6_PD_LEASE_RENEW %1: lease for prefix %2/%3 and iaid=%4 has been allocated

This informational message indicates that in response to a client's REQUEST message, the server successfully renewed a prefix lease. This is a normal behavior and indicates successful operation. The first argument includes the client and transaction identification information. The remaining arguments hold the allocated prefix, prefix length and and IAID.

DHCP6_PROCESS_IA_NA_EXTEND %1: extending lease lifetime for IA_NA option with iaid=%2

This message is logged when the server is starting to extend the lifetime of the address lease associated with the particular IAID. The first argument includes the client and transaction identification information. The second argument contains the IAID.

DHCP6_PROCESS_IA_NA_RELEASE %1: releasing lease for IA_NA option with iaid=%2

This message is logged when the server is trying to release the client's as a result of receiving the RELEASE message. The first argument includes the client and transaction identification information. The second argument contains the IAID.

DHCP6_PROCESS_IA_NA_REQUEST %1: server is processing IA_NA option with iaid=%2 and hint=%3

This is a debug message that indicates the processing of a received IA_NA option. The first argument contains the client and the transaction identification information. The second argument holds the IAID of the IA_NA option. The third argument may hold the hint for the server about the address that the client would like to have allocated. If there is no hint, the argument should provide the text indicating that the hint hasn't been sent.

DHCP6_PROCESS_IA_PD_EXTEND %1: extending lease lifetime for IA_PD option with iaid=%2

This message is logged when the server is starting to extend the lifetime of the prefix lease associated with the particular IAID. The first argument includes the client and transaction identification information. The second argument contains the IAID.

DHCP6_PROCESS_IA_PD_REQUEST %1: server is processing IA_PD option with iaid=%2 and hint=%3

This is a debug message that indicates a processing of received IA_PD option. The first argument contains the client and the transaction identification information. The second argument holds the IAID of the IA_PD option. The third argument may hold the hint for the server about the prefix that the client would like to have allocated. If there is no hint, the argument should provide the text indicating that the hint hasn't been sent.

DHCP6_QUERY_DATA %1, packet details: %2

A debug message printing the details of the received packet. The first argument includes the client and the transaction identification information.

DHCP6_RAPID_COMMIT %1: Rapid Commit option received, following 2-way exchange

This debug message is issued when the server found a Rapid Commit option in the client's message and 2-way exchanges are supported by the server for the subnet on which the client is connected. The argument specifies the client and transaction identification information.

DHCP6_RELEASE_NA %1: binding for address %2 and iaid=%3 was released properly

This informational message indicates that an address was released properly. It is a normal operation during client shutdown.

DHCP6_RELEASE_NA_FAIL %1: failed to remove address lease for address %2 and iaid=%3

This error message indicates that the software failed to remove an address lease from the lease database. It probably due to an error during a database operation: resolution will most likely require administrator intervention (e.g. check if DHCP process has sufficient privileges to update the database). It may also be triggered if a lease was manually removed from the database during RELEASE message processing. The first argument holds the client and transaction identification information. The second and third argument hold the released address and IAID respectively.

DHCP6_RELEASE_NA_FAIL_WRONG_DUID %1: client tried to release address %2, but it belongs to another client using duid=%3

This warning message indicates that a client tried to release an address that belongs to a different client. This should not happen in normal circumstances and may indicate a misconfiguration of the client. However, since the client releasing the address will stop using it anyway, there is a good chance that the situation will correct itself.

DHCP6_RELEASE_NA_FAIL_WRONG_IAID %1: client tried to release address %2, but it used wrong IAID (expected %3, but got %4)

This warning message indicates that client tried to release an address that does belong to it, but the address was expected to be in a different IA (identity association) container. This probably means that the client's support for multiple addresses is flawed.

DHCP6_RELEASE_PD %1: prefix %2/%3 for iaid=%4 was released properly

This informational message indicates that a prefix was released properly. It is a normal operation during client shutdown. The first argument holds the client and transaction identification information. The second and third argument define the prefix and its length. The fourth argument holds IAID.

DHCP6_RELEASE_PD_FAIL %1: failed to release prefix %2/%3 for iaid=%4

This error message indicates that the software failed to remove a prefix lease from the lease database. It probably due to an error during a database operation: resolution will most likely require administrator intervention (e.g. check if DHCP process has sufficient privileges to update the database). It may also be triggered if a lease was manually removed from the database during RELEASE message processing. The first argument hold the client and transaction identification information. The second and third argument define the prefix and its length. The fourth argument holds the IAID.

DHCP6_RELEASE_PD_FAIL_WRONG_DUID %1: client tried to release prefix %2/%3, but it belongs to another client (duid=%4)

This warning message indicates that client tried to release a prefix that belongs to a different client. This should not happen in normal circumstances and may indicate a misconfiguration of the client. However, since the client releasing the prefix will stop using it anyway, there is a good chance that the situation will correct itself. The first argument includes the client and the transaction identification information. The second and third argument include the prefix and prefix length. The last argument holds the DUID of the client holding the lease.

DHCP6_RELEASE_PD_FAIL_WRONG_IAID %1: client tried to release prefix %2/%3, but it used wrong IAID (expected %4, but got %5)

This warning message indicates that client tried to release a prefix that does belong to it, but the address was expected to be in a different IA (identity association) container. This probably means that the client's support for multiple prefixes is flawed. The first argument includes the client and transaction identification information. The second and third argument identify the prefix. The fourth and fifth argument hold the expected IAID and IAID found respectively.

DHCP6_REQUIRED_OPTIONS_CHECK_FAIL %1 message received from %2 failed the following check: %3

This message indicates that received DHCPv6 packet is invalid. This may be due to a number of reasons, e.g. the mandatory client-id option is missing, the server-id forbidden in that particular type of message is present, there is more than one instance of client-id or server-id present, etc. The exact reason for rejecting the packet is included in the message.

DHCP6_RESPONSE_DATA responding with packet type %1 data is %2

A debug message listing the data returned to the client.

DHCP6_SERVER_FAILED server failed: %1

The IPv6 DHCP server has encountered a fatal error and is terminating. The reason for the failure is included in the message.

DHCP6_SHUTDOWN server shutdown

The IPv6 DHCP server has terminated normally.

DHCP6_SHUTDOWN_REQUEST shutdown of server requested

This debug message indicates that a shutdown of the IPv6 server has been requested via a call to the 'shutdown' method of the core Dhcpv6Srv object.

DHCP6_SOCKET_UNICAST server is about to open socket on address %1 on interface %2

This is a debug message that inform that a unicast socket will be opened.

DHCP6_SRV_CONSTRUCT_ERROR error creating Dhcpv6Srv object, reason: %1

This error message indicates that during startup, the construction of a core component within the IPv6 DHCP server (the Dhcpv6 server object) has failed. As a result, the server will exit. The reason for the failure is given within the message.

DHCP6_SRV_D2STOP_ERROR error stopping IO with DHCP_DDNS during shutdown: %1

This error message indicates that during shutdown, an error occurred while stopping IO between the DHCPv6 server and the DHCP_DDNS server. This is probably due to a programmatic error is not likely to impact either server upon restart. The reason for the failure is given within the message.

DHCP6_STANDALONE skipping message queue, running standalone

This is a debug message indicating that the IPv6 server is running in standalone mode, not connected to the message queue. Standalone mode is only useful during program development, and should not be used in a production environment.

DHCP6_STARTED Kea DHCPv6 server version %1 started

This informational message indicates that the IPv6 DHCP server has processed all configuration information and is ready to process DHCPv6 packets. The version is also printed.

DHCP6_STARTING Kea DHCPv6 server version %1 starting

This informational message indicates that the IPv6 DHCP server has processed any command-line switches and is starting. The version is also printed.

DHCP6_START_INFO pid: %1, port: %2, verbose: %3

This is a debug message issued during the IPv6 DHCP server startup. It lists some information about the parameters with which the server is running.

DHCP6_SUBNET_DATA %1: the selected subnet details: %2

This debug message includes the details of the subnet selected for the client. The first argument includes the client and the transaction identification information. The second argument includes the subnet details.

DHCP6_SUBNET_SELECTED %1: the subnet with ID %2 was selected for client assignments

This is a debug message noting the selection of a subnet to be used for address and option assignment. Subnet selection is one of the early steps in the processing of incoming client message. The first argument includes the client and the transaction identification information. The second argument holds the selected subnet id.

DHCP6_SUBNET_SELECTION_FAILED %1: failed to select subnet for the client

This debug message indicates that the server failed to select the subnet for the client which has sent a message to the server. The cause is likely due to a misconfiguration of the server. The packet processing will continue, but the response will only contain generic configuration and no addresses or prefixes. The argument includes the client and the transaction identification information.

DHCP6_UNKNOWN_MSG_RECEIVED received unknown message (type %d) on interface %2

This debug message is printed when server receives a message of unknown type. That could either mean missing functionality or invalid or broken relay or client. The list of formally defined message types is available here: http://www.iana.org/assignments/dhcpv6-parameters.

DHCP6_USING_SERVERID server is using server-id %1 and stores in the file %2

This info message is logged when the server reads its server-id from a file or generates it. This message is a notification to the administrator what server-id will be used and where it is persisted. Typically, there is no need to modify the server id. However, it is possible to do it in the Kea configuration file. It is important to understand the implications of such modification. The clients will remember previous server-id, and will use it to extend their leases. As a result, they will have to go through a rebinding phase to re-acquire their leases and associate them with a new server id.

DHCPRSV Module

DHCPRSV_MEMFILE_CONVERTING_LEASE_FILES running LFC now to convert lease files to the current schema: %1.%2

A warning message issued when the server has detected lease files that need to be either upgraded or downgraded to match the server's schema, and that the server is automatically running the LFC process to perform the conversion. This should only occur the first time the server is launched following a Kea installation upgrade (or downgrade).

DHCPSRV Module

DHCPSRV_CFGMGR_ADD_IFACE listening on interface %1

An info message issued when a new interface is being added to the collection of interfaces on which the server listens to DHCP messages.

DHCPSRV_CFGMGR_ADD_SUBNET4 adding subnet %1

A debug message reported when the DHCP configuration manager is adding the specified IPv4 subnet to its database.

DHCPSRV_CFGMGR_ADD_SUBNET6 adding subnet %1

A debug message reported when the DHCP configuration manager is adding the specified IPv6 subnet to its database.

DHCPSRV_CFGMGR_ALL_IFACES_ACTIVE enabling listening on all interfaces

A debug message issued when the server is being configured to listen on all interfaces.

DHCPSRV_CFGMGR_CFG_DHCP_DDNS Setting DHCP-DDNS configuration to: %1

A debug message issued when the server's DHCP-DDNS settings are changed.

DHCPSRV_CFGMGR_CLEAR_ACTIVE_IFACES stop listening on all interfaces

A debug message issued when configuration manager clears the internal list of active interfaces. This doesn't prevent the server from listening to the DHCP traffic through open sockets, but will rather be used by Interface Manager to select active interfaces when sockets are re-opened.

DHCPSRV_CFGMGR_CONFIGURE_SERVERID server configuration includes specification of a server identifier

This warning message is issued when the server specified configuration of a server identifier. If this new configuration overrides an existing server identifier, this will affect existing bindings of the clients. Clients will use old server identifier when they renew their bindings. The server will not respond to those renews, and the clients will eventually transition to rebinding state. The server should reassign existing bindings and the clients will subsequently use new server identifier. It is recommended to not modify the server identifier, unless there is a good reason for it, to avoid increased number of renewals and a need for rebinding (increase of multicast traffic, which may be received by multiple servers).

DHCPSRV_CFGMGR_NO_SUBNET4 no suitable subnet is defined for address hint %1

This debug message is output when the DHCP configuration manager has received a request for an IPv4 subnet for the specified address, but no such subnet exists.

DHCPSRV_CFGMGR_NO_SUBNET6 no suitable subnet is defined for address hint %1

This debug message is output when the DHCP configuration manager has received a request for an IPv6 subnet for the specified address, but no such subnet exists.

DHCPSRV_CFGMGR_ONLY_SUBNET4 retrieved subnet %1 for address hint %2

This is a debug message reporting that the DHCP configuration manager has returned the specified IPv4 subnet when given the address hint specified because it is the only subnet defined.

DHCPSRV_CFGMGR_ONLY_SUBNET6 retrieved subnet %1 for address hint %2

This is a debug message reporting that the DHCP configuration manager has returned the specified IPv6 subnet when given the address hint specified because it is the only subnet defined.

DHCPSRV_CFGMGR_SOCKET_RAW_UNSUPPORTED use of raw sockets is unsupported on this OS, UDP sockets will be used

This warning message is logged when the user specified that the DHCPv4 server should use the raw sockets to receive the DHCP messages and respond to the clients, but the use of raw sockets is not supported on the particular environment. The raw sockets are useful when the server must respond to the directly connected clients which don't have an address yet. If the raw sockets are not supported by Kea on the particular platform, Kea will fall back to use of the IP/UDP sockets. The responses to the directly connected clients will be broadcast. The responses to relayed clients will be unicast as usual.

DHCPSRV_CFGMGR_SOCKET_TYPE_DEFAULT "dhcp-socket-type" not specified , using default socket type %1

This informational message is logged when the administrator hasn't specified the "dhcp-socket-type" parameter in configuration for interfaces. In such case, the default socket type will be used.

DHCPSRV_CFGMGR_SOCKET_TYPE_SELECT using socket type %1

This informational message is logged when the DHCPv4 server selects the socket type to be used for all sockets that will be opened on the interfaces. Typically, the socket type is specified by the server administrator. If the socket type hasn't been specified, the raw socket will be selected. If the raw socket has been selected but Kea doesn't support the use of raw sockets on the particular OS, it will use an UDP socket instead.

DHCPSRV_CFGMGR_SUBNET4 retrieved subnet %1 for address hint %2

This is a debug message reporting that the DHCP configuration manager has returned the specified IPv4 subnet when given the address hint specified as the address is within the subnet.

DHCPSRV_CFGMGR_SUBNET4_ADDR selected subnet %1 for packet received by matching address %2

This is a debug message reporting that the DHCP configuration manager has returned the specified IPv4 subnet for a received packet. This particular subnet was selected, because an IPv4 address was matched which belonged to that subnet.

DHCPSRV_CFGMGR_SUBNET4_IFACE selected subnet %1 for packet received over interface %2

This is a debug message reporting that the DHCP configuration manager has returned the specified IPv4 subnet for a packet received over the given interface. This particular subnet was selected, because it was specified as being directly reachable over the given interface. (see 'interface' parameter in the subnet4 definition).

DHCPSRV_CFGMGR_SUBNET4_RELAY selected subnet %1, because of matching relay addr %2

This is a debug message reporting that the DHCP configuration manager has returned the specified IPv4 subnet, because detected relay agent address matches value specified for this subnet.

DHCPSRV_CFGMGR_SUBNET6 retrieved subnet %1 for address hint %2

This is a debug message reporting that the DHCP configuration manager has returned the specified IPv6 subnet when given the address hint specified as the address is within the subnet.

DHCPSRV_CFGMGR_SUBNET6_IFACE selected subnet %1 for packet received over interface %2

This is a debug message reporting that the DHCP configuration manager has returned the specified IPv6 subnet for a packet received over given interface. This particular subnet was selected, because it was specified as being directly reachable over given interface. (see 'interface' parameter in the subnet6 definition).

DHCPSRV_CFGMGR_SUBNET6_IFACE_ID selected subnet %1 (interface-id match) for incoming packet

This is a debug message reporting that the DHCP configuration manager has returned the specified IPv6 subnet for a received packet. This particular subnet was selected, because value of interface-id option matched what was configured in the server's interface-id option for that selected subnet6. (see 'interface-id' parameter in the subnet6 definition).

DHCPSRV_CFGMGR_SUBNET6_RELAY selected subnet %1, because of matching relay addr %2

This is a debug message reporting that the DHCP configuration manager has returned the specified IPv6 subnet, because detected relay agent address matches value specified for this subnet.

DHCPSRV_CFGMGR_UNICAST_LINK_LOCAL specified link local address %1 for unicast traffic on interface %2

This warning message is logged when user specified a link-local address to receive unicast traffic. The warning message is issued because it is an uncommon use.

DHCPSRV_CFGMGR_USE_ADDRESS listening on address %1, on interface %2

A message issued when the server is configured to listen on the explicitly specified IP address on the given interface.

DHCPSRV_CFGMGR_USE_UNICAST listening on unicast address %1, on interface %2

An info message issued when configuring the DHCP server to listen on the unicast address on the specific interface.

DHCPSRV_CLOSE_DB closing currently open %1 database

This is a debug message, issued when the DHCP server closes the currently open lease database. It is issued at program shutdown and whenever the database access parameters are changed: in the latter case, the server closes the currently open database, and opens a database using the new parameters.

DHCPSRV_CQL_ADD_ADDR4 adding IPv4 lease with address %1

A debug message issued when the server is about to add an IPv4 lease with the specified address to the Cassandra backend database.

DHCPSRV_CQL_ADD_ADDR6 adding IPv6 lease with address %1

A debug message issued when the server is about to add an IPv6 lease with the specified address to the Cassandra backend database.

DHCPSRV_CQL_COMMIT committing to Cassandra database

A commit call been issued on the server. For Cassandra, this is a no-op.

DHCPSRV_CQL_DB opening Cassandra lease database: %1

This informational message is logged when a DHCP server (either V4 or V6) is about to open a Cassandra lease database. The parameters of the connection including database name and username needed to access it (but not the password if any) are logged.

DHCPSRV_CQL_DELETE_ADDR deleting lease for address %1

A debug message issued when the server is attempting to delete a lease from the Cassandra database for the specified address.

DHCPSRV_CQL_DELETE_EXPIRED_RECLAIMED4 deleting reclaimed IPv4 leases that expired more than %1 seconds ago

A debug message issued when the server is removing reclaimed DHCPv4 leases which have expired longer than a specified period of time. The argument is the amount of time Kea waits after a reclaimed lease expires before considering its removal.

DHCPSRV_CQL_DELETE_EXPIRED_RECLAIMED6 deleting reclaimed IPv6 leases that expired more than %1 seconds ago

A debug message issued when the server is removing reclaimed DHCPv6 leases which have expired longer than a specified period of time. The argument is the amount of time Kea waits after a reclaimed lease expires before considering its removal.

DHCPSRV_CQL_GET_ADDR4 obtaining IPv4 lease for address %1

A debug message issued when the server is attempting to obtain an IPv4 lease from the Cassandra database for the specified address.

DHCPSRV_CQL_GET_ADDR6 obtaining IPv6 lease for address %1 and lease type %2

A debug message issued when the server is attempting to obtain an IPv6 lease from the Cassandra database for the specified address.

DHCPSRV_CQL_GET_CLIENTID obtaining IPv4 leases for client ID %1

A debug message issued when the server is attempting to obtain a set of IPv4 leases from the Cassandra database for a client with the specified client identification.

DHCPSRV_CQL_GET_CLIENTID_HWADDR_SUBID obtaining IPv4 lease for client ID %1, hardware address %2 and subnet ID %3

A debug message issued when the server is attempting to obtain an IPv4 lease from the Cassandra database for a client with the specified client ID, hardware address and subnet ID.

DHCPSRV_CQL_GET_EXPIRED4 obtaining maximum %1 of expired IPv4 leases

A debug message issued when the server is attempting to obtain expired IPv4 leases to reclaim them. The maximum number of leases to be retrieved is logged in the message.

DHCPSRV_CQL_GET_EXPIRED6 obtaining maximum %1 of expired IPv6 leases

A debug message issued when the server is attempting to obtain expired IPv6 leases to reclaim them. The maximum number of leases to be retrieved is logged in the message.

DHCPSRV_CQL_GET_HWADDR obtaining IPv4 leases for hardware address %1

A debug message issued when the server is attempting to obtain a set of IPv4 leases from the Cassandra database for a client with the specified hardware address.

DHCPSRV_CQL_GET_IAID_DUID obtaining IPv6 leases for IAID %1 and DUID %2 and lease type %3

A debug message issued when the server is attempting to obtain a set of IPv6 leases from the Cassandra database for a client with the specified IAID (Identity Association ID) and DUID (DHCP Unique Identifier).

DHCPSRV_CQL_GET_IAID_SUBID_DUID obtaining IPv6 leases for IAID %1, Subnet ID %2, DUID %3 and lease type %4

A debug message issued when the server is attempting to obtain an IPv6 lease from the Cassandra database for a client with the specified IAID (Identity Association ID), Subnet ID and DUID (DHCP Unique Identifier).

DHCPSRV_CQL_GET_SUBID_CLIENTID obtaining IPv4 lease for subnet ID %1 and client ID %2

A debug message issued when the server is attempting to obtain an IPv4 lease from the Cassandra database for a client with the specified subnet ID and client ID.

DHCPSRV_CQL_GET_SUBID_HWADDR obtaining IPv4 lease for subnet ID %1 and hardware address %2

A debug message issued when the server is attempting to obtain an IPv4 lease from the Cassandra database for a client with the specified subnet ID and hardware address.

DHCPSRV_CQL_GET_VERSION obtaining schema version information

A debug message issued when the server is about to obtain schema version information from the Cassandra database.

DHCPSRV_CQL_ROLLBACK rolling back Cassandra database

The code has issued a rollback call. For Cassandra, this is a no-op.

DHCPSRV_CQL_UPDATE_ADDR4 updating IPv4 lease for address %1

A debug message issued when the server is attempting to update IPv4 lease from the Cassandra database for the specified address.

DHCPSRV_CQL_UPDATE_ADDR6 updating IPv6 lease for address %1

A debug message issued when the server is attempting to update IPv6 lease from the Cassandra database for the specified address.

DHCPSRV_DHCP4O6_RECEIVED_BAD_PACKET received bad DHCPv4o6 packet: %1

A bad DHCPv4o6 packet was received.

DHCPSRV_DHCP_DDNS_ERROR_EXCEPTION error handler for DHCP_DDNS IO generated an expected exception: %1

This is an error message that occurs when an attempt to send a request to kea-dhcp-ddns fails there registered error handler threw an uncaught exception. This is a programmatic error which should not occur. By convention, the error handler should not propagate exceptions. Please report this error.

DHCPSRV_DHCP_DDNS_HANDLER_NULL error handler for DHCP_DDNS IO is not set.

This is an error message that occurs when an attempt to send a request to kea-dhcp-ddns fails and there is no registered error handler. This is a programmatic error which should never occur and should be reported.

DHCPSRV_DHCP_DDNS_NCR_REJECTED NameChangeRequest rejected by the sender: %1, ncr: %2

This is an error message indicating that NameChangeSender used to deliver DDNS update requests to kea-dhcp-ddns rejected the request. This most likely cause is the sender's queue has reached maximum capacity. This would imply that requests are being generated faster than they can be delivered.

DHCPSRV_DHCP_DDNS_NCR_SENT NameChangeRequest sent to kea-dhcp-ddns: %1

A debug message issued when a NameChangeRequest has been successfully sent to kea-dhcp-ddns.

DHCPSRV_DHCP_DDNS_SENDER_STARTED NameChangeRequest sender has been started: %1

A informational message issued when a communications with kea-dhcp-ddns has been successfully started.

DHCPSRV_DHCP_DDNS_SENDER_STOPPED NameChangeRequest sender has been stopped.

A informational message issued when a communications with kea-dhcp-ddns has been stopped. This normally occurs during reconfiguration and as part of normal shutdown. It may occur if kea-dhcp-ddns communications breakdown.

DHCPSRV_DHCP_DDNS_SUSPEND_UPDATES DHCP_DDNS updates are being suspended.

This is a warning message indicating the DHCP_DDNS updates have been turned off. This should only occur if IO errors communicating with kea-dhcp-ddns have been experienced. Any such errors should have preceding entries in the log with details. No further attempts to communicate with kea-dhcp-ddns will be made without intervention.

DHCPSRV_HOOK_LEASE4_RECOVER_SKIP DHCPv4 lease %1 was not recovered from the declined state because a callout set the skip status.

This debug message is printed when a callout installed on lease4_recover hook point set the next step status to SKIP. For this particular hook point, this indicates that the server should not recover the lease from declined state. The server will leave the lease as it is, in the declined state. The server will attempt to recover it the next time decline recovery procedure takes place.

DHCPSRV_HOOK_LEASE4_RENEW_SKIP DHCPv4 lease was not renewed because a callout set the skip flag.

This debug message is printed when a callout installed on lease4_renew hook point set the skip flag. For this particular hook point, the setting of the flag by a callout instructs the server to not renew a lease. The server will use existing lease as it is, without extending its lifetime.

DHCPSRV_HOOK_LEASE4_SELECT_SKIP Lease4 creation was skipped, because of callout skip flag.

This debug message is printed when a callout installed on lease4_select hook point sets the skip flag. It means that the server was told that no lease4 should be assigned. The server will not put that lease in its database and the client will get a NAK packet.

DHCPSRV_HOOK_LEASE6_EXTEND_SKIP DHCPv6 lease lifetime was not extended because a callout set the skip flag for message %1

This debug message is printed when a callout installed on lease6_renew or the lease6_rebind hook point set the skip flag. For this particular hook point, the setting of the flag by a callout instructs the server to not extend the lifetime for a lease. If the client requested renewal of multiple leases (by sending multiple IA options), the server will skip the renewal of the one in question and will proceed with other renewals as usual.

DHCPSRV_HOOK_LEASE6_RECOVER_SKIP DHCPv6 lease %1 was not recovered from declined state because a callout set the skip status.

This debug message is printed when a callout installed on lease6_recover hook point set the next step status to SKIP. For this particular hook point, this indicates that the server should not recover the lease from declined state. The server will leave the lease as it is, in the declined state. The server will attempt to recover it the next time decline recovery procedure takes place.

DHCPSRV_HOOK_LEASE6_SELECT_SKIP Lease6 (non-temporary) creation was skipped, because of callout skip flag.

This debug message is printed when a callout installed on lease6_select hook point sets the skip flag. It means that the server was told that no lease6 should be assigned. The server will not put that lease in its database and the client will get a NoAddrsAvail for that IA_NA option.

DHCPSRV_INVALID_ACCESS invalid database access string: %1

This is logged when an attempt has been made to parse a database access string and the attempt ended in error. The access string in question - which should be of the form 'keyword=value keyword=value...' is included in the message.

DHCPSRV_MEMFILE_ADD_ADDR4 adding IPv4 lease with address %1

A debug message issued when the server is about to add an IPv4 lease with the specified address to the memory file backend database.

DHCPSRV_MEMFILE_ADD_ADDR6 adding IPv6 lease with address %1

A debug message issued when the server is about to add an IPv6 lease with the specified address to the memory file backend database.

DHCPSRV_MEMFILE_COMMIT committing to memory file database

The code has issued a commit call. For the memory file database, this is a no-op.

DHCPSRV_MEMFILE_DB opening memory file lease database: %1

This informational message is logged when a DHCP server (either V4 or V6) is about to open a memory file lease database. The parameters of the connection including database name and username needed to access it (but not the password if any) are logged.

DHCPSRV_MEMFILE_DELETE_ADDR deleting lease for address %1

A debug message issued when the server is attempting to delete a lease for the specified address from the memory file database for the specified address.

DHCPSRV_MEMFILE_DELETE_EXPIRED_RECLAIMED4 deleting reclaimed IPv4 leases that expired more than %1 seconds ago

A debug message issued when the server is removing reclaimed DHCPv4 leases which have expired longer than a specified period of time. The argument is the amount of time Kea waits after a reclaimed lease expires before considering its removal.

DHCPSRV_MEMFILE_DELETE_EXPIRED_RECLAIMED6 deleting reclaimed IPv6 leases that expired more than %1 seconds ago

A debug message issued when the server is removing reclaimed DHCPv6 leases which have expired longer than a specified period of time. The argument is the amount of time Kea waits after a reclaimed lease expires before considering its removal.

DHCPSRV_MEMFILE_DELETE_EXPIRED_RECLAIMED_START starting deletion of %1 expired-reclaimed leases

A debug message issued when the server has found expired-reclaimed leases to be removed. The number of leases to be removed is logged in the message.

DHCPSRV_MEMFILE_GET_ADDR4 obtaining IPv4 lease for address %1

A debug message issued when the server is attempting to obtain an IPv4 lease from the memory file database for the specified address.

DHCPSRV_MEMFILE_GET_ADDR6 obtaining IPv6 lease for address %1 and lease type %2

A debug message issued when the server is attempting to obtain an IPv6 lease from the memory file database for the specified address.

DHCPSRV_MEMFILE_GET_CLIENTID obtaining IPv4 leases for client ID %1

A debug message issued when the server is attempting to obtain a set of IPv4 leases from the memory file database for a client with the specified client identification.

DHCPSRV_MEMFILE_GET_CLIENTID_HWADDR_SUBID obtaining IPv4 lease for client ID %1, hardware address %2 and subnet ID %3

A debug message issued when the server is attempting to obtain an IPv4 lease from the memory file database for a client with the specified client ID, hardware address and subnet ID.

DHCPSRV_MEMFILE_GET_EXPIRED4 obtaining maximum %1 of expired IPv4 leases

A debug message issued when the server is attempting to obtain expired IPv4 leases to reclaim them. The maximum number of leases to be retrieved is logged in the message.

DHCPSRV_MEMFILE_GET_EXPIRED6 obtaining maximum %1 of expired IPv6 leases

A debug message issued when the server is attempting to obtain expired IPv6 leases to reclaim them. The maximum number of leases to be retrieved is logged in the message.

DHCPSRV_MEMFILE_GET_HWADDR obtaining IPv4 leases for hardware address %1

A debug message issued when the server is attempting to obtain a set of IPv4 leases from the memory file database for a client with the specified hardware address.

DHCPSRV_MEMFILE_GET_IAID_DUID obtaining IPv6 leases for IAID %1 and DUID %2 and lease type %3

A debug message issued when the server is attempting to obtain a set of IPv6 leases from the memory file database for a client with the specified IAID (Identity Association ID) and DUID (DHCP Unique Identifier).

DHCPSRV_MEMFILE_GET_IAID_SUBID_DUID obtaining IPv6 leases for IAID %1, Subnet ID %2, DUID %3 and lease type %4

A debug message issued when the server is attempting to obtain an IPv6 lease from the memory file database for a client with the specified IAID (Identity Association ID), Subnet ID and DUID (DHCP Unique Identifier).

DHCPSRV_MEMFILE_GET_SUBID_CLIENTID obtaining IPv4 lease for subnet ID %1 and client ID %2

A debug message issued when the server is attempting to obtain an IPv4 lease from the memory file database for a client with the specified subnet ID and client ID.

DHCPSRV_MEMFILE_GET_SUBID_HWADDR obtaining IPv4 lease for subnet ID %1 and hardware address %2

A debug message issued when the server is attempting to obtain an IPv4 lease from the memory file database for a client with the specified subnet ID and hardware address.

DHCPSRV_MEMFILE_GET_VERSION obtaining schema version information

A debug message issued when the server is about to obtain schema version information from the memory file database.

DHCPSRV_MEMFILE_LEASE_FILE_LOAD loading leases from file %1

An info message issued when the server is about to start reading DHCP leases from the lease file. All leases currently held in the memory will be replaced by those read from the file.

DHCPSRV_MEMFILE_LEASE_LOAD loading lease %1

A debug message issued when DHCP lease is being loaded from the file to memory.

DHCPSRV_MEMFILE_LFC_EXECUTE executing Lease File Cleanup using: %1

An informational message issued when the Memfile lease database backend starts a new process to perform Lease File Cleanup.

DHCPSRV_MEMFILE_LFC_LEASE_FILE_RENAME_FAIL failed to rename the current lease file %1 to %2, reason: %3

An error message logged when the Memfile lease database backend fails to move the current lease file to a new file on which the cleanup should be performed. This effectively means that the lease file cleanup will not take place.

DHCPSRV_MEMFILE_LFC_LEASE_FILE_REOPEN_FAIL failed to reopen lease file %1 after preparing input file for lease file cleanup, reason: %2, new leases will not be persisted!

An error message logged when the Memfile lease database backend failed to re-open or re-create the lease file after renaming the lease file for lease file cleanup. The server will continue to operate but leases will not be persisted to disk.

DHCPSRV_MEMFILE_LFC_SETUP setting up the Lease File Cleanup interval to %1 sec

An informational message logged when the Memfile lease database backend configures the LFC to be executed periodically. The argument holds the interval in seconds in which the LFC will be executed.

DHCPSRV_MEMFILE_LFC_SPAWN_FAIL lease file cleanup failed to run because kea-lfc process couldn't be spawned

This error message is logged when the Kea server fails to run kea-lfc, the program that cleans up the lease file. The server will try again the next time a lease file cleanup is scheduled. Although this message should not appear and the reason why it did investigated, the occasional failure to start the lease file cleanup will not impact operations. Should the failure persist however, the size of the lease file will increase without bound.

DHCPSRV_MEMFILE_LFC_START starting Lease File Cleanup

An informational message issued when the Memfile lease database backend starts the periodic Lease File Cleanup.

DHCPSRV_MEMFILE_LFC_UNREGISTER_TIMER_FAILED failed to unregister timer 'memfile-lfc': %1

This debug message is logged when Memfile backend fails to unregister timer used for lease file cleanup scheduling. There are several reasons why this could occur, although the most likely cause is that the system is being shut down and some other component has unregistered the timer. The message includes the reason for this error.

DHCPSRV_MEMFILE_NEEDS_DOWNGRADING version of lease file: %1 schema is later than version %2

A warning message issued when the schema of the lease file loaded by the server is newer than the memfile schema of the server. The server converts the lease data from newer schemas to its schema as it is read, therefore the lease information in use by the server will be correct. Note though, that any data stored in newer schema fields will be dropped. What remains is for the file itself to be rewritten using the current schema.

DHCPSRV_MEMFILE_NEEDS_UPGRADING version of lease file: %1 schema is earlier than version %2

A warning message issued when the schema of the lease file loaded by the server pre-dates the memfile schema of the server. Note that the server converts the lease data from older schemas to the current schema as it is read, therefore the lease information in use by the server will be correct. What remains is for the file itself to be rewritten using the current schema.

DHCPSRV_MEMFILE_NO_STORAGE running in non-persistent mode, leases will be lost after restart

A warning message issued when writes of leases to disk have been disabled in the configuration. This mode is useful for some kinds of performance testing but should not be enabled in normal circumstances. Non-persistence mode is enabled when 'persist4=no persist6=no' parameters are specified in the database access string.

DHCPSRV_MEMFILE_READ_HWADDR_FAIL failed to read hardware address from lease file: %1

A warning message issued when read attempt of the hardware address stored in a disk file failed. The parameter should provide the exact nature of the failure. The database read will continue, but that particular lease will no longer have hardware address associated with it.

DHCPSRV_MEMFILE_ROLLBACK rolling back memory file database

The code has issued a rollback call. For the memory file database, this is a no-op.

DHCPSRV_MEMFILE_UPDATE_ADDR4 updating IPv4 lease for address %1

A debug message issued when the server is attempting to update IPv4 lease from the memory file database for the specified address.

DHCPSRV_MEMFILE_UPDATE_ADDR6 updating IPv6 lease for address %1

A debug message issued when the server is attempting to update IPv6 lease from the memory file database for the specified address.

DHCPSRV_MULTIPLE_RAW_SOCKETS_PER_IFACE current configuration will result in opening multiple broadcast capable sockets on some interfaces and some DHCP messages may be duplicated

A warning message issued when the current configuration indicates that multiple sockets, capable of receiving broadcast traffic, will be opened on some of the interfaces. It must be noted that this may lead to receiving and processing the same DHCP message multiple times, as it will be received by each socket individually.

DHCPSRV_MYSQL_ADD_ADDR4 adding IPv4 lease with address %1

A debug message issued when the server is about to add an IPv4 lease with the specified address to the MySQL backend database.

DHCPSRV_MYSQL_ADD_ADDR6 adding IPv6 lease with address %1, lease type %2

A debug message issued when the server is about to add an IPv6 lease with the specified address to the MySQL backend database.

DHCPSRV_MYSQL_COMMIT committing to MySQL database

The code has issued a commit call. All outstanding transactions will be committed to the database. Note that depending on the MySQL settings, the committal may not include a write to disk.

DHCPSRV_MYSQL_DB opening MySQL lease database: %1

This informational message is logged when a DHCP server (either V4 or V6) is about to open a MySQL lease database. The parameters of the connection including database name and username needed to access it (but not the password if any) are logged.

DHCPSRV_MYSQL_DELETED_EXPIRED_RECLAIMED deleted %1 reclaimed leases from the database

A debug message issued when the server has removed a number of reclaimed leases from the database. The number of removed leases is included in the message.

DHCPSRV_MYSQL_DELETE_ADDR deleting lease for address %1

A debug message issued when the server is attempting to delete a lease for the specified address from the MySQL database for the specified address.

DHCPSRV_MYSQL_DELETE_EXPIRED_RECLAIMED4 deleting reclaimed IPv4 leases that expired more than %1 seconds ago

A debug message issued when the server is removing reclaimed DHCPv4 leases which have expired longer than a specified period of time. The argument is the amount of time Kea waits after a reclaimed lease expires before considering its removal.

DHCPSRV_MYSQL_DELETE_EXPIRED_RECLAIMED6 deleting reclaimed IPv6 leases that expired more than %1 seconds ago

A debug message issued when the server is removing reclaimed DHCPv6 leases which have expired longer than a specified period of time. The argument is the amount of time Kea waits after a reclaimed lease expires before considering its removal.

DHCPSRV_MYSQL_FATAL_ERROR Unrecoverable MySQL error occurred: %1 for <%2>, reason: %3 (error code: %4). Server exiting now!

An error message indicating that communication with the MySQL database server has been lost. When this occurs the server exits immediately with a non-zero exit code. This is most likely due to a network issue.

DHCPSRV_MYSQL_GET_ADDR4 obtaining IPv4 lease for address %1

A debug message issued when the server is attempting to obtain an IPv4 lease from the MySQL database for the specified address.

DHCPSRV_MYSQL_GET_ADDR6 obtaining IPv6 lease for address %1, lease type %2

A debug message issued when the server is attempting to obtain an IPv6 lease from the MySQL database for the specified address.

DHCPSRV_MYSQL_GET_CLIENTID obtaining IPv4 leases for client ID %1

A debug message issued when the server is attempting to obtain a set of IPv4 leases from the MySQL database for a client with the specified client identification.

DHCPSRV_MYSQL_GET_EXPIRED4 obtaining maximum %1 of expired IPv4 leases

A debug message issued when the server is attempting to obtain expired IPv4 leases to reclaim them. The maximum number of leases to be retrieved is logged in the message.

DHCPSRV_MYSQL_GET_EXPIRED6 obtaining maximum %1 of expired IPv6 leases

A debug message issued when the server is attempting to obtain expired IPv6 leases to reclaim them. The maximum number of leases to be retrieved is logged in the message.

DHCPSRV_MYSQL_GET_HWADDR obtaining IPv4 leases for hardware address %1

A debug message issued when the server is attempting to obtain a set of IPv4 leases from the MySQL database for a client with the specified hardware address.

DHCPSRV_MYSQL_GET_IAID_DUID obtaining IPv6 leases for IAID %1, DUID %2, lease type %3

A debug message issued when the server is attempting to obtain a set of IPv6 leases from the MySQL database for a client with the specified IAID (Identity Association ID) and DUID (DHCP Unique Identifier).

DHCPSRV_MYSQL_GET_IAID_SUBID_DUID obtaining IPv6 leases for IAID %1, Subnet ID %2, DUID %3, lease type %4

A debug message issued when the server is attempting to obtain an IPv6 lease from the MySQL database for a client with the specified IAID (Identity Association ID), Subnet ID and DUID (DHCP Unique Identifier).

DHCPSRV_MYSQL_GET_SUBID_CLIENTID obtaining IPv4 lease for subnet ID %1 and client ID %2

A debug message issued when the server is attempting to obtain an IPv4 lease from the MySQL database for a client with the specified subnet ID and client ID.

DHCPSRV_MYSQL_GET_SUBID_HWADDR obtaining IPv4 lease for subnet ID %1 and hardware address %2

A debug message issued when the server is attempting to obtain an IPv4 lease from the MySQL database for a client with the specified subnet ID and hardware address.

DHCPSRV_MYSQL_GET_VERSION obtaining schema version information

A debug message issued when the server is about to obtain schema version information from the MySQL database.

DHCPSRV_MYSQL_HOST_DB opening MySQL hosts database: %1

This informational message is logged when a DHCP server (either V4 or V6) is about to open a MySQL hosts database. The parameters of the connection including database name and username needed to access it (but not the password if any) are logged.

DHCPSRV_MYSQL_HOST_DB_GET_VERSION obtaining schema version information for the MySQL hosts database

A debug message issued when the server is about to obtain schema version information from the MySQL hosts database.

DHCPSRV_MYSQL_HOST_DB_READONLY MySQL host database opened for read access only

This informational message is issued when the user has configured the MySQL database in read-only mode. Kea will not be able to insert or modify host reservations but will be able to retrieve existing ones and assign them to the clients communicating with the server.

DHCPSRV_MYSQL_ROLLBACK rolling back MySQL database

The code has issued a rollback call. All outstanding transaction will be rolled back and not committed to the database.

DHCPSRV_MYSQL_START_TRANSACTION starting new MySQL transaction

A debug message issued whena new MySQL transaction is being started. This message is typically not issued when inserting data into a single table because the server doesn't explicitly start transactions in this case. This message is issued when data is inserted into multiple tables with multiple INSERT statements and there may be a need to rollback the whole transaction if any of these INSERT statements fail.

DHCPSRV_MYSQL_UPDATE_ADDR4 updating IPv4 lease for address %1

A debug message issued when the server is attempting to update IPv4 lease from the MySQL database for the specified address.

DHCPSRV_MYSQL_UPDATE_ADDR6 updating IPv6 lease for address %1, lease type %2

A debug message issued when the server is attempting to update IPv6 lease from the MySQL database for the specified address.

DHCPSRV_NOTYPE_DB no 'type' keyword to determine database backend: %1

This is an error message, logged when an attempt has been made to access a database backend, but where no 'type' keyword has been included in the access string. The access string (less any passwords) is included in the message.

DHCPSRV_NO_SOCKETS_OPEN no interface configured to listen to DHCP traffic

This warning message is issued when the current server configuration specifies no interfaces that the server should listen on, or when the specified interfaces are not configured to receive the traffic.

DHCPSRV_OPEN_SOCKET_FAIL failed to open socket: %1

A warning message issued when IfaceMgr fails to open and bind a socket. The reason for the failure is appended as an argument of the log message.

DHCPSRV_PGSQL_ADD_ADDR4 adding IPv4 lease with address %1

A debug message issued when the server is about to add an IPv4 lease with the specified address to the PostgreSQL backend database.

DHCPSRV_PGSQL_ADD_ADDR6 adding IPv6 lease with address %1

A debug message issued when the server is about to add an IPv6 lease with the specified address to the PostgreSQL backend database.

DHCPSRV_PGSQL_COMMIT committing to MySQL database

The code has issued a commit call. All outstanding transactions will be committed to the database. Note that depending on the PostgreSQL settings, the committal may not include a write to disk.

DHCPSRV_PGSQL_DB opening PostgreSQL lease database: %1

This informational message is logged when a DHCP server (either V4 or V6) is about to open a PostgreSQL lease database. The parameters of the connection including database name and username needed to access it (but not the password if any) are logged.

DHCPSRV_PGSQL_DEALLOC_ERROR An error occurred deallocating SQL statements while closing the PostgreSQL lease database: %1

This is an error message issued when a DHCP server (either V4 or V6) experienced and error freeing database SQL resources as part of closing its connection to the Postgresql database. The connection is closed as part of normal server shutdown. This error is most likely a programmatic issue that is highly unlikely to occur or negatively impact server operation.

DHCPSRV_PGSQL_DELETE_ADDR deleting lease for address %1

A debug message issued when the server is attempting to delete a lease for the specified address from the PostgreSQL database for the specified address.

DHCPSRV_PGSQL_DELETE_EXPIRED_RECLAIMED4 deleting reclaimed IPv4 leases that expired more than %1 seconds ago

A debug message issued when the server is removing reclaimed DHCPv4 leases which have expired longer than a specified period of time. The argument is the amount of time Kea waits after a reclaimed lease expires before considering its removal.

DHCPSRV_PGSQL_DELETE_EXPIRED_RECLAIMED6 deleting reclaimed IPv6 leases that expired more than %1 seconds ago

A debug message issued when the server is removing reclaimed DHCPv6 leases which have expired longer than a specified period of time. The argument is the amount of time Kea waits after a reclaimed lease expires before considering its removal.

DHCPSRV_PGSQL_FATAL_ERROR Unrecoverable PostgreSQL error occurred: Statement: <%1>, reason: %2 (error code: %3). Server exiting now!

An error message indicating that communication with the MySQL database server has been lost. When this occurs the server exits immediately with a non-zero exit code. This is most likely due to a network issue.

DHCPSRV_PGSQL_GET_ADDR4 obtaining IPv4 lease for address %1

A debug message issued when the server is attempting to obtain an IPv4 lease from the PostgreSQL database for the specified address.

DHCPSRV_PGSQL_GET_ADDR6 obtaining IPv6 lease for address %1 (lease type %2)

A debug message issued when the server is attempting to obtain an IPv6 lease from the PostgreSQL database for the specified address.

DHCPSRV_PGSQL_GET_CLIENTID obtaining IPv4 leases for client ID %1

A debug message issued when the server is attempting to obtain a set of IPv4 leases from the PostgreSQL database for a client with the specified client identification.

DHCPSRV_PGSQL_GET_EXPIRED4 obtaining maximum %1 of expired IPv4 leases

A debug message issued when the server is attempting to obtain expired IPv4 leases to reclaim them. The maximum number of leases to be retrieved is logged in the message.

DHCPSRV_PGSQL_GET_EXPIRED6 obtaining maximum %1 of expired IPv6 leases

A debug message issued when the server is attempting to obtain expired IPv6 leases to reclaim them. The maximum number of leases to be retrieved is logged in the message.

DHCPSRV_PGSQL_GET_HWADDR obtaining IPv4 leases for hardware address %1

A debug message issued when the server is attempting to obtain a set of IPv4 leases from the PostgreSQL database for a client with the specified hardware address.

DHCPSRV_PGSQL_GET_IAID_DUID obtaining IPv4 leases for IAID %1 and DUID %2, lease type %3

A debug message issued when the server is attempting to obtain a set of IPv6 leases from the PostgreSQL database for a client with the specified IAID (Identity Association ID) and DUID (DHCP Unique Identifier).

DHCPSRV_PGSQL_GET_IAID_SUBID_DUID obtaining IPv4 leases for IAID %1, Subnet ID %2, DUID %3, and lease type %4

A debug message issued when the server is attempting to obtain an IPv6 lease from the PostgreSQL database for a client with the specified IAID (Identity Association ID), Subnet ID and DUID (DHCP Unique Identifier).

DHCPSRV_PGSQL_GET_SUBID_CLIENTID obtaining IPv4 lease for subnet ID %1 and client ID %2

A debug message issued when the server is attempting to obtain an IPv4 lease from the PostgreSQL database for a client with the specified subnet ID and client ID.

DHCPSRV_PGSQL_GET_SUBID_HWADDR obtaining IPv4 lease for subnet ID %1 and hardware address %2

A debug message issued when the server is attempting to obtain an IPv4 lease from the PostgreSQL database for a client with the specified subnet ID and hardware address.

DHCPSRV_PGSQL_GET_VERSION obtaining schema version information

A debug message issued when the server is about to obtain schema version information from the PostgreSQL database.

DHCPSRV_PGSQL_HOST_DB opening PostgreSQL hosts database: %1

This informational message is logged when a DHCP server (either V4 or V6) is about to open a PostgreSQL hosts database. The parameters of the connection including database name and username needed to access it (but not the password if any) are logged.

DHCPSRV_PGSQL_HOST_DB_GET_VERSION obtaining schema version information for the PostgreSQL hosts database

A debug message issued when the server is about to obtain schema version information from the PostgreSQL hosts database.

DHCPSRV_PGSQL_HOST_DB_READONLY PostgreSQL host database opened for read access only

This informational message is issued when the user has configured the PostgreSQL database in read-only mode. Kea will not be able to insert or modify host reservations but will be able to retrieve existing ones and assign them to the clients communicating with the server.

DHCPSRV_PGSQL_ROLLBACK rolling back PostgreSQL database

The code has issued a rollback call. All outstanding transaction will be rolled back and not committed to the database.

DHCPSRV_PGSQL_START_TRANSACTION starting a new PostgreSQL transaction

A debug message issued when a new PostgreSQL transaction is being started. This message is typically not issued when inserting data into a single table because the server doesn't explicitly start transactions in this case. This message is issued when data is inserted into multiple tables with multiple INSERT statements and there may be a need to rollback the whole transaction if any of these INSERT statements fail.

DHCPSRV_PGSQL_UPDATE_ADDR4 updating IPv4 lease for address %1

A debug message issued when the server is attempting to update IPv4 lease from the PostgreSQL database for the specified address.

DHCPSRV_PGSQL_UPDATE_ADDR6 updating IPv6 lease for address %1

A debug message issued when the server is attempting to update IPv6 lease from the PostgreSQL database for the specified address.

DHCPSRV_QUEUE_NCR %1: name change request to %2 DNS entry queued: %3

A debug message which is logged when the NameChangeRequest to add or remove a DNS entries for a particular lease has been queued. The first argument includes the client identification information. The second argument indicates whether the DNS entry is to be added or removed. The third argument carries the details of the NameChangeRequest.

DHCPSRV_QUEUE_NCR_FAILED %1: queueing %2 name change request failed for lease %3: %4

This error message is logged when sending a name change request to DHCP DDNS failed. The first argument includes the client identification information. The second argument indicates whether the DNS entry is to be added or removed. The third argument specifies the leased address. The last argument provides the reason for failure.

DHCPSRV_QUEUE_NCR_SKIP %1: skip queueing name change request for lease: %2

This debug message is issued when the server decides to not queue the name change request because the lease doesn't include the FQDN, the forward and reverse update is disabled for this lease or the DNS updates are disabled in the configuration. The first argument includes the client identification information. The second argument includes the leased address.

DHCPSRV_TIMERMGR_CALLBACK_FAILED running handler for timer %1 caused exception: %2

This error message is emitted when the timer elapsed and the operation associated with this timer has thrown an exception. The timer name and the reason for exception is logged.

DHCPSRV_TIMERMGR_REGISTER_TIMER registering timer: %1, using interval: %2 ms

A debug message issued when the new interval timer is registered in the Timer Manager. This timer will have a callback function associated with it, and this function will be executed according to the interval specified. The unique name of the timer and the interval at which the callback function will be executed is included in the message.

DHCPSRV_TIMERMGR_RUN_TIMER_OPERATION running operation for timer: %1

A debug message issued when the Timer Manager is about to run a periodic operation associated with the given timer. An example of such operation is a periodic cleanup of expired leases. The name of the timer is included in the message.

DHCPSRV_TIMERMGR_SOCKET_CLEAR_FAILED clearing watch socket for timer %1 failed: %2

An error message indicating that the specified timer elapsed, the operation associated with the timer was executed but the server was unable to signal this to the worker thread responsible for dispatching timers. The thread will continue but it will not be able to dispatch any operations for this timer. The server reconfiguration or restart may solve the problem but the situation may repeat.

DHCPSRV_TIMERMGR_SOCKET_MARK_FAILED marking watch socket for timer %1 failed: %2

An error message indicating that the specified timer elapsed, but the server was unable to flag that the handler function should be executed for this timer. The callback will not be executed this time and most likely the subsequent attempts will not be successful too. This error is highly unlikely. The name of the timer and the reason for failure is included in the message.

DHCPSRV_TIMERMGR_START_THREAD starting thread for timers

A debug message issued when the Timer Manager is starting a worker thread to run started timers. The worker thread is typically started right after all timers have been registered and runs until timers need to be reconfigured, e.g. their interval is changed, new timers are registered or existing timers are unregistered.

DHCPSRV_TIMERMGR_START_TIMER starting timer: %1

A debug message issued when the registered interval timer is being started. If this operation is successful the timer will periodically execute the operation associated with it. The name of the started timer is included in the message.

DHCPSRV_TIMERMGR_STOP_THREAD stopping thread for timers

A debug message issued when the Timer Manager is stopping the worker thread which executes interval timers. When the thread is stopped no timers will be executed. The thread is typically stopped at the server reconfiguration or when the server shuts down.

DHCPSRV_TIMERMGR_STOP_TIMER stopping timer: %1

A debug message issued when the registered interval timer is being stopped. The timer remains registered and can be restarted if necessary. The name of the timer is included in the message.

DHCPSRV_TIMERMGR_UNREGISTER_ALL_TIMERS unregistering all timers

A debug message issued when all registered interval timers are being unregistered from the Timer Manager.

DHCPSRV_TIMERMGR_UNREGISTER_TIMER unregistering timer: %1

A debug message issued when one of the registered interval timers is unregistered from the Timer Manager. The name of the timer is included in the message.

DHCPSRV_UNEXPECTED_NAME database access parameters passed through '%1', expected 'lease-database'

The parameters for access the lease database were passed to the server through the named configuration parameter, but the code was expecting them to be passed via the parameter named "lease-database". If the database opens successfully, there is no impact on server operation. However, as this does indicate an error in the source code, please submit a bug report.

DHCPSRV_UNKNOWN_DB unknown database type: %1

The database access string specified a database type (given in the message) that is unknown to the software. This is a configuration error.

DHCP Module

DHCP_DDNS_ADD_FAILED DHCP_DDNS Request ID %1: Transaction outcome %2

This is an error message issued after DHCP_DDNS attempts to submit DNS mapping entry additions have failed. The precise reason for the failure should be documented in preceding log entries.

DHCP_DDNS_ADD_SUCCEEDED DHCP_DDNS Request ID %1: successfully added the DNS mapping addition for this request: %2

This is an informational message issued after DHCP_DDNS has submitted DNS mapping additions which were received and accepted by an appropriate DNS server.

DHCP_DDNS_ALREADY_RUNNING %1 already running? %2

This is an error message that occurs when DHCP_DDNS encounters a pre-existing PID file which contains the PID of a running process. This most likely indicates an attempt to start a second instance of DHCP_DDNS using the same configuration file. It is possible, though unlikely, that the PID file is a remnant left behind by a server crash or power failure and the PID it contains refers to a process other than DHCP_DDNS. In such an event, it would be necessary to manually remove the PID file. The first argument is the DHCP_DDNS process name, the second contains the PID and PID file.

DHCP_DDNS_AT_MAX_TRANSACTIONS application has %1 queued requests but has reached maximum number of %2 concurrent transactions

This is a debug message that indicates that the application has DHCP_DDNS requests in the queue but is working as many concurrent requests as allowed.

DHCP_DDNS_CFG_FILE_RELOAD_ERROR configuration reload failed: %1, reverting to current configuration.

This is an error message indicating that the application attempted to reload its configuration from file and encountered an error. This is likely due to invalid content in the configuration file. The application should continue to operate under its current configuration.

DHCP_DDNS_CFG_FILE_RELOAD_SIGNAL_RECVD OS signal %1 received, reloading configuration from file: %2

This is an informational message indicating the application has received a signal instructing it to reload its configuration from file.

DHCP_DDNS_CLEARED_FOR_SHUTDOWN application has met shutdown criteria for shutdown type: %1

This is a debug message issued when the application has been instructed to shutdown and has met the required criteria to exit.

DHCP_DDNS_COMMAND command directive received, command: %1 - args: %2

This is a debug message issued when the DHCP-DDNS application command method has been invoked.

DHCP_DDNS_CONFIGURE configuration update received: %1

This is a debug message issued when the DHCP-DDNS application configure method has been invoked.

DHCP_DDNS_FAILED application experienced a fatal error: %1

This is a debug message issued when the DHCP-DDNS application encounters an unrecoverable error from within the event loop.

DHCP_DDNS_FORWARD_ADD_BAD_DNSCLIENT_STATUS DHCP_DDNS Request ID %1: received an unknown DNSClient status: %2, while adding a forward address mapping for FQDN %3 to DNS server %4

This is an error message issued when DNSClient returns an unrecognized status while DHCP_DDNS was adding a forward address mapping. The request will be aborted. This is most likely a programmatic issue and should be reported.

DHCP_DDNS_FORWARD_ADD_BUILD_FAILURE DNS Request ID %1: update message to add a forward DNS entry could not be constructed for this request: %2, reason: %3

This is an error message issued when an error occurs attempting to construct the server bound packet requesting a forward address addition. This is due to invalid data contained in the NameChangeRequest. The request will be aborted. This is most likely a configuration issue.

DHCP_DDNS_FORWARD_ADD_IO_ERROR DHCP_DDNS Request ID %1: encountered an IO error sending a forward mapping add for FQDN %2 to DNS server %3

This is an error message issued when a communication error occurs while DHCP_DDNS is carrying out a forward address update. The application will retry against the same server or others as appropriate.

DHCP_DDNS_FORWARD_ADD_REJECTED DNS Request ID %1: Server, %2, rejected a DNS update request to add the address mapping for FQDN, %3, with an RCODE: %4

This is an error message issued when an update was rejected by the DNS server it was sent to for the reason given by the RCODE. The rcode values are defined in RFC 2136.

DHCP_DDNS_FORWARD_ADD_RESP_CORRUPT DHCP_DDNS Request ID %1: received a corrupt response from the DNS server, %2, while adding forward address mapping for FQDN, %3

This is an error message issued when the response received by DHCP_DDNS, to a update request to add a forward address mapping, is mangled or malformed. The application will retry against the same server or others as appropriate.

DHCP_DDNS_FORWARD_REMOVE_ADDRS_BAD_DNSCLIENT_STATUS DHCP_DDNS Request ID %1: received an unknown DNSClient status: %2, while removing a forward address mapping for FQDN %3 to DNS server %4

This is an error message issued when DNSClient returns an unrecognized status while DHCP_DDNS was removing a forward address mapping. The request will be aborted. This is most likely a programmatic issue and should be reported.

DHCP_DDNS_FORWARD_REMOVE_ADDRS_BUILD_FAILURE DNS Request ID %1: update message to remove a forward DNS Address entry could not be constructed for this request: %2, reason: %3

This is an error message issued when an error occurs attempting to construct the server bound packet requesting a forward address (A or AAAA) removal. This is due to invalid data contained in the NameChangeRequest. The request will be aborted. This is most likely a configuration issue. /*sar*/

DHCP_DDNS_FORWARD_REMOVE_ADDRS_IO_ERROR DHCP_DDNS Request ID %1: encountered an IO error sending a forward mapping address removal for FQDN %2 to DNS server %3

This is an error message issued when a communication error occurs while DHCP_DDNS is carrying out a forward address remove. The application will retry against the same server or others as appropriate.

DHCP_DDNS_FORWARD_REMOVE_ADDRS_REJECTED DNS Request ID %1: Server, %2, rejected a DNS update request to remove the forward address mapping for FQDN, %3, with an RCODE: %4

This is an error message issued when an update was rejected by the DNS server it was sent to for the reason given by the RCODE. The rcode values are defined in RFC 2136.

DHCP_DDNS_FORWARD_REMOVE_ADDRS_RESP_CORRUPT DHCP_DDNS Request ID %1: received a corrupt response from the DNS server, %2, while removing forward address mapping for FQDN, %3

This is an error message issued when the response received by DHCP_DDNS, to a update request to remove a forward address mapping, is mangled or malformed. The application will retry against the same server or others as appropriate.

DHCP_DDNS_FORWARD_REMOVE_RRS_BAD_DNSCLIENT_STATUS DHCP_DDNS Request ID %1: received an unknown DNSClient status: %2, while removing forward RRs for FQDN %3 to DNS server %4

This is an error message issued when DNSClient returns an unrecognized status while DHCP_DDNS was removing forward RRs. The request will be aborted. This is most likely a programmatic issue and should be reported.

DHCP_DDNS_FORWARD_REMOVE_RRS_BUILD_FAILURE DNS Request ID %1: update message to remove forward DNS RR entries could not be constructed for this request: %2, reason: %3

This is an error message issued when an error occurs attempting to construct the server bound packet requesting forward RR (DHCID RR) removal. This is due to invalid data contained in the NameChangeRequest. The request will be aborted. This is most likely a configuration issue.

DHCP_DDNS_FORWARD_REMOVE_RRS_IO_ERROR DHCP_DDNS Request ID %1: encountered an IO error sending a forward RR removal for FQDN %2 to DNS server %3

This is an error message issued when a communication error occurs while DHCP_DDNS is carrying out a forward RR remove. The application will retry against the same server.

DHCP_DDNS_FORWARD_REMOVE_RRS_REJECTED DNS Request ID %1: Server, %2, rejected a DNS update request to remove forward RR entries for FQDN, %3, with an RCODE: %4

This is an error message issued when an update was rejected by the DNS server it was sent to for the reason given by the RCODE. The rcode values are defined in RFC 2136.

DHCP_DDNS_FORWARD_REMOVE_RRS_RESP_CORRUPT DHCP_DDNS Request ID %1: received a corrupt response from the DNS server, %2, while removing forward RRs for FQDN, %3

This is an error message issued when the response received by DHCP_DDNS, to a update request to remove forward RRs mapping, is mangled or malformed. The application will retry against the same server or others as appropriate. /*sar*/

DHCP_DDNS_FORWARD_REPLACE_BAD_DNSCLIENT_STATUS DHCP_DDNS Request ID %1: received an unknown DNSClient status: %2, while replacing forward address mapping for FQDN %3 to DNS server %4

This is an error message issued when DNSClient returns an unrecognized status while DHCP_DDNS was replacing a forward address mapping. The request will be aborted. This is most likely a programmatic issue and should be reported.

DHCP_DDNS_FORWARD_REPLACE_BUILD_FAILURE DNS Request ID %1: update message to replace a forward DNS entry could not be constructed from this request: %2, reason: %3

This is an error message issued when an error occurs attempting to construct the server bound packet requesting a forward address replacement. This is due to invalid data contained in the NameChangeRequest. The request will be aborted. This is most likely a configuration issue.

DHCP_DDNS_FORWARD_REPLACE_IO_ERROR DHCP_DDNS Request ID %1: encountered an IO error sending a forward mapping replace for FQDN %2 to DNS server %3

This is an error message issued when a communication error occurs while DHCP_DDNS is carrying out a forward address update. The application will retry against the same server or others as appropriate.

DHCP_DDNS_FORWARD_REPLACE_REJECTED DNS Request ID %1: Server, %2, rejected a DNS update request to replace the address mapping for FQDN, %3, with an RCODE: %4

This is an error message issued when an update was rejected by the DNS server it was sent to for the reason given by the RCODE. The rcode values are defined in RFC 2136.

DHCP_DDNS_FORWARD_REPLACE_RESP_CORRUPT DHCP_DDNS Request ID %1: received a corrupt response from the DNS server, %2, while replacing forward address mapping for FQDN, %3

This is an error message issued when the response received by DHCP_DDNS, to a update request to replace a forward address mapping, is mangled or malformed. The application will retry against the same server or others as appropriate.

DHCP_DDNS_FWD_REQUEST_IGNORED Request ID %1: Forward updates are disabled, the forward portion of request will be ignored: %2

This is a debug message issued when forward DNS updates are disabled and DHCP_DDNS receives an update request containing a forward DNS update. The forward update will not performed.

DHCP_DDNS_INVALID_NCR application received an invalid DNS update request: %1

This is an error message that indicates that an invalid request to update a DNS entry was received by the application. Either the format or the content of the request is incorrect. The request will be ignored.

DHCP_DDNS_INVALID_RESPONSE received response to DNS Update message is malformed: %1

This is a debug message issued when the DHCP-DDNS application encountered an error while decoding a response to DNS Update message. Typically, this error will be encountered when a response message is malformed.

DHCP_DDNS_NCR_FLUSH_IO_ERROR DHCP-DDNS Last send before stopping did not complete successfully: %1

This is an error message that indicates the DHCP-DDNS client was unable to complete the last send prior to exiting send mode. This is a programmatic error, highly unlikely to occur, and should not impair the application's ability to process requests.

DHCP_DDNS_NCR_LISTEN_CLOSE_ERROR application encountered an error while closing the listener used to receive NameChangeRequests : %1

This is an error message that indicates the application was unable to close the listener connection used to receive NameChangeRequests. Closure may occur during the course of error recovery or during normal shutdown procedure. In either case the error is unlikely to impair the application's ability to process requests but it should be reported for analysis.

DHCP_DDNS_NCR_RECV_NEXT_ERROR application could not initiate the next read following a request receive.

This is a error message indicating that NameChangeRequest listener could not start another read after receiving a request. While possible, this is highly unlikely and is probably a programmatic error. The application should recover on its own.

DHCP_DDNS_NCR_SEND_CLOSE_ERROR DHCP-DDNS client encountered an error while closing the sender connection used to send NameChangeRequests: %1

This is an error message that indicates the DHCP-DDNS client was unable to close the connection used to send NameChangeRequests. Closure may occur during the course of error recovery or during normal shutdown procedure. In either case the error is unlikely to impair the client's ability to send requests but it should be reported for analysis.

DHCP_DDNS_NCR_SEND_NEXT_ERROR DHCP-DDNS client could not initiate the next request send following send completion: %1

This is a error message indicating that NameChangeRequest sender could not start another send after completing the send of the previous request. While possible, this is highly unlikely and is probably a programmatic error. The application should recover on its own.

DHCP_DDNS_NCR_UDP_CLEAR_READY_ERROR NCR UDP watch socket failed to clear: %1

This is an error message that indicates the application was unable to reset the UDP NCR sender ready status after completing a send. This is programmatic error that should be reported. The application may or may not continue to operate correctly.

DHCP_DDNS_NCR_UDP_RECV_CANCELED UDP socket receive was canceled while listening for DNS Update requests

This is a debug message indicating that the listening on a UDP socket for DNS update requests has been canceled. This is a normal part of suspending listening operations.

DHCP_DDNS_NCR_UDP_RECV_ERROR UDP socket receive error while listening for DNS Update requests: %1

This is an error message indicating that an I/O error occurred while listening over a UDP socket for DNS update requests. This could indicate a network connectivity or system resource issue.

DHCP_DDNS_NCR_UDP_SEND_CANCELED UDP socket send was canceled while sending a DNS Update request to DHCP_DDNS: %1

This is an informational message indicating that sending requests via UDP socket to DHCP_DDNS has been interrupted. This is a normal part of suspending send operations.

DHCP_DDNS_NCR_UDP_SEND_ERROR UDP socket send error while sending a DNS Update request: %1

This is an error message indicating that an IO error occurred while sending a DNS update request to DHCP_DDNS over a UDP socket. This could indicate a network connectivity or system resource issue.

DHCP_DDNS_NOT_ON_LOOPBACK the DHCP-DDNS server has been configured to listen on %1 which is not the local loopback. This is an insecure configuration supported for testing purposes only

This is a warning message issued when the DHCP-DDNS server is configured to listen at an address other than the loopback address (127.0.0.1 or ::1). It is possible for a malicious attacker to send bogus NameChangeRequests to it and change entries in the DNS. For this reason, addresses other than the IPv4 or IPv6 loopback addresses should only be used for testing purposes. A future version of Kea will implement authentication to guard against such attacks.

DHCP_DDNS_NO_ELIGIBLE_JOBS although there are queued requests, there are pending transactions for each, Queue count: %1 Transaction count: %2

This is a debug message issued when all of the queued requests represent clients for which there is a an update already in progress. This may occur under normal operations but should be temporary situation.

DHCP_DDNS_NO_FWD_MATCH_ERROR Request ID %1: the configured list of forward DDNS domains does not contain a match for: %2 The request has been discarded.

This is an error message that indicates that DHCP_DDNS received a request to update a the forward DNS information for the given FQDN but for which there are no configured DDNS domains in the DHCP_DDNS configuration. Either the DHCP_DDNS configuration needs to be updated or the source of the FQDN itself should be investigated.

DHCP_DDNS_NO_MATCH No DNS servers match FQDN %1

This is warning message issued when there are no domains in the configuration which match the cited fully qualified domain name (FQDN). The DNS Update request for the FQDN cannot be processed.

DHCP_DDNS_NO_REV_MATCH_ERROR Request ID %1: the configured list of reverse DDNS domains does not contain a match for: %2 The request has been discarded.

This is an error message that indicates that DHCP_DDNS received a request to update a the reverse DNS information for the given FQDN but for which there are no configured DDNS domains in the DHCP_DDNS configuration. Either the DHCP_DDNS configuration needs to be updated or the source of the FQDN itself should be investigated.

DHCP_DDNS_PID_FILE_ERROR %1 could not create a PID file: %2

This is an error message that occurs when DHCP_DDNS is unable to create its PID file. The log message should contain details sufficient to determine the underlying cause. The most likely culprits are that some portion of the pathname does not exist or a permissions issue. The default path is determined by --localstatedir configure parameter but may be overridden by setting environment variable, KEA_PIDFILE_DIR. The first argument is the DHCP_DDNS process name.

DHCP_DDNS_PROCESS_INIT application init invoked

This is a debug message issued when the DHCP-DDNS application enters its initialization method.

DHCP_DDNS_QUEUE_MGR_QUEUE_FULL application request queue has reached maximum number of entries %1

This an error message indicating that DHCP-DDNS is receiving DNS update requests faster than they can be processed. This may mean the maximum queue needs to be increased, the DHCP-DDNS clients are simply generating too many requests too quickly, or perhaps upstream DNS servers are experiencing load issues.

DHCP_DDNS_QUEUE_MGR_QUEUE_RECEIVE Request ID %1: received and queued a request.

This is an informational message indicating that the NameChangeREquest listener used by DHCP-DDNS to receive a request has received a request and queued it for further processing.

DHCP_DDNS_QUEUE_MGR_RECONFIGURING application is reconfiguring the queue manager

This is an informational message indicating that DHCP_DDNS is reconfiguring the queue manager as part of normal startup or in response to a new configuration.

DHCP_DDNS_QUEUE_MGR_RECOVERING application is attempting to recover from a queue manager IO error

This is an informational message indicating that DHCP_DDNS is attempting to restart the queue manager after it suffered an IO error while receiving requests.

DHCP_DDNS_QUEUE_MGR_RECV_ERROR application's queue manager was notified of a request receive error by its listener.

This is an error message indicating that the NameChangeRequest listener used by DHCP-DDNS to receive requests encountered an IO error. There should be corresponding log messages from the listener layer with more details. This may indicate a network connectivity or system resource issue.

DHCP_DDNS_QUEUE_MGR_RESUME_ERROR application could not restart the queue manager, reason: %1

This is an error message indicating that DHCP_DDNS's Queue Manager could not be restarted after stopping due to a full receive queue. This means that the application cannot receive requests. This is most likely due to DHCP_DDNS configuration parameters referring to resources such as an IP address or port, that is no longer unavailable. DHCP_DDNS will attempt to restart the queue manager if given a new configuration.

DHCP_DDNS_QUEUE_MGR_RESUMING application is resuming listening for requests now that the request queue size has reached %1 of a maximum %2 allowed

This is an informational message indicating that DHCP_DDNS, which had stopped accepting new requests, has processed enough entries from the receive queue to resume accepting requests.

DHCP_DDNS_QUEUE_MGR_STARTED application's queue manager has begun listening for requests.

This is a debug message indicating that DHCP_DDNS's Queue Manager has successfully started and is now listening for NameChangeRequests.

DHCP_DDNS_QUEUE_MGR_START_ERROR application could not start the queue manager, reason: %1

This is an error message indicating that DHCP_DDNS's Queue Manager could not be started. This means that the application cannot receive requests. This is most likely due to DHCP_DDNS configuration parameters referring to resources such as an IP address or port, that are unavailable. DHCP_DDNS will attempt to restart the queue manager if given a new configuration.

DHCP_DDNS_QUEUE_MGR_STOPPED application's queue manager has stopped listening for requests.

This is a debug message indicating that DHCP_DDNS's Queue Manager has stopped listening for NameChangeRequests. This may be because of normal event such as reconfiguration or as a result of an error. There should be log messages preceding this one to indicate why it has stopped.

DHCP_DDNS_QUEUE_MGR_STOPPING application is stopping the queue manager for %1

This is an informational message indicating that DHCP_DDNS is stopping the queue manager either to reconfigure it or as part of application shutdown.

DHCP_DDNS_QUEUE_MGR_STOP_ERROR application encountered an error stopping the queue manager: %1

This is an error message indicating that DHCP_DDNS encountered an error while trying to stop the queue manager. This error is unlikely to occur or to impair the application's ability to function but it should be reported for analysis.

DHCP_DDNS_QUEUE_MGR_UNEXPECTED_HANDLER_ERROR application's queue manager request receive handler experienced an unexpected exception %1:

This is an error message indicating that an unexpected error occurred within the DHCP_DDNS's Queue Manager request receive completion handler. This is most likely a programmatic issue that should be reported. The application may recover on its own.

DHCP_DDNS_QUEUE_MGR_UNEXPECTED_STOP application's queue manager receive was

aborted unexpectedly while queue manager state is: %1 This is an error message indicating that DHCP_DDNS's Queue Manager request receive was unexpected interrupted. Normally, the read is receive is only interrupted as a normal part of stopping the queue manager. This is most likely a programmatic issue that should be reported.

DHCP_DDNS_REMOVE_FAILED DHCP_DDNS Request ID %1: Transaction outcome: %2

This is an error message issued after DHCP_DDNS attempts to submit DNS mapping entry removals have failed. The precise reason for the failure should be documented in preceding log entries.

DHCP_DDNS_REMOVE_SUCCEEDED DHCP_DDNS Request ID %1: successfully removed the DNS mapping addition for this request: %2

This is an informational message issued after DHCP_DDNS has submitted DNS mapping removals which were received and accepted by an appropriate DNS server.

DHCP_DDNS_REQUEST_DROPPED Request ID %1: Request contains no enabled update requests and will be dropped: %2

This is a debug message issued when DHCP_DDNS receives a request which does not contain updates in a direction that is enabled. In other words, if only forward updates are enabled and request is received that asks only for reverse updates then the request is dropped.

DHCP_DDNS_REVERSE_REMOVE_BAD_DNSCLIENT_STATUS DHCP_DDNS Request ID %1: received an unknown DNSClient status: %2, while removing reverse address mapping for FQDN %3 to DNS server %4

This is an error message issued when DNSClient returns an unrecognized status while DHCP_DDNS was removing a reverse address mapping. The request will be aborted. This is most likely a programmatic issue and should be reported.

DHCP_DDNS_REVERSE_REMOVE_BUILD_FAILURE DNS Request ID %1: update message to remove a reverse DNS entry could not be constructed from this request: %2, reason: %3

This is an error message issued when an error occurs attempting to construct the server bound packet requesting a reverse PTR removal. This is due to invalid data contained in the NameChangeRequest. The request will be aborted. This is most likely a configuration issue.

DHCP_DDNS_REVERSE_REMOVE_IO_ERROR DHCP_DDNS Request ID %1: encountered an IO error sending a reverse mapping remove for FQDN %2 to DNS server %3

This is an error message issued when a communication error occurs while DHCP_DDNS is carrying out a reverse address update. The application will retry against the same server or others as appropriate.

DHCP_DDNS_REVERSE_REMOVE_REJECTED DNS Request ID %1: Server, %2, rejected a DNS update request to remove the reverse mapping for FQDN, %3, with an RCODE: %4

This is an error message issued when an update was rejected by the DNS server it was sent to for the reason given by the RCODE. The rcode values are defined in RFC 2136.

DHCP_DDNS_REVERSE_REMOVE_RESP_CORRUPT DHCP_DDNS Request ID %1: received a corrupt response from the DNS server, %2, while removing reverse address mapping for FQDN, %3

This is an error message issued when the response received by DHCP_DDNS, to a update request to remove a reverse address, is mangled or malformed. The application will retry against the same server or others as appropriate.

DHCP_DDNS_REVERSE_REPLACE_BAD_DNSCLIENT_STATUS DHCP_DDNS Request ID %1: received an unknown DNSClient status: %2, while replacing reverse address mapping for FQDN %3 to DNS server %4

This is an error message issued when DNSClient returns an unrecognized status while DHCP_DDNS was replacing a reverse address mapping. The request will be aborted. This is most likely a programmatic issue and should be reported.

DHCP_DDNS_REVERSE_REPLACE_BUILD_FAILURE DNS Request ID %1: update message to replace a reverse DNS entry could not be constructed from this request: %2, reason: %3

This is an error message issued when an error occurs attempting to construct the server bound packet requesting a reverse PTR replacement. This is due to invalid data contained in the NameChangeRequest. The request will be aborted. This is most likely a configuration issue.

DHCP_DDNS_REVERSE_REPLACE_IO_ERROR DHCP_DDNS Request ID %1: encountered an IO error sending a reverse mapping replacement for FQDN %2 to DNS server %3

This is an error message issued when a communication error occurs while DHCP_DDNS is carrying out a reverse address update. The application will retry against the same server or others as appropriate.

DHCP_DDNS_REVERSE_REPLACE_REJECTED DNS Request ID %1: Server, %2, rejected a DNS update request to replace the reverse mapping for FQDN, %3, with an RCODE: %4

This is an error message issued when an update was rejected by the DNS server it was sent to for the reason given by the RCODE. The rcode values are defined in RFC 2136.

DHCP_DDNS_REVERSE_REPLACE_RESP_CORRUPT DHCP_DDNS Request ID %1: received a corrupt response from the DNS server, %2, while replacing reverse address mapping for FQDN, %3

This is an error message issued when the response received by DHCP_DDNS, to a update request to replace a reverse address, is mangled or malformed. The application will retry against the same server or others as appropriate.

DHCP_DDNS_REV_REQUEST_IGNORED Request ID %1: Reverse updates are disabled, the reverse portion of request will be ignored: %2

This is a debug message issued when reverse DNS updates are disabled and DHCP_DDNS receives an update request containing a reverse DNS update. The reverse update will not performed.

DHCP_DDNS_RUN_EXIT application is exiting the event loop

This is a debug message issued when the DHCP-DDNS server exits its event lo

DHCP_DDNS_SHUTDOWN DHCP-DDNS has shut down

This is an informational message indicating that the DHCP-DDNS service has shut down.

DHCP_DDNS_SHUTDOWN_COMMAND application received shutdown command with args: %1

This is a debug message issued when the application has been instructed to shut down by the controller.

DHCP_DDNS_SHUTDOWN_SIGNAL_RECVD OS signal %1 received, starting shutdown

This is a debug message indicating the application has received a signal instructing it to shutdown.

DHCP_DDNS_SIGNAL_ERROR signal handler for signal %1, threw an unexpected exception: %2

This is an error message indicating that the application encountered an unexpected error after receiving a signal. This is a programmatic error and should be reported. While The application will likely continue to operating, it may be unable to respond correctly to signals.

DHCP_DDNS_STARTED Kea DHCP-DDNS server version %1 started

This informational message indicates that the DHCP-DDNS server has processed all configuration information and is ready to begin processing. The version is also printed.

DHCP_DDNS_STARTING DHCP-DDNS starting, pid: %1, version: %2

This is an informational message issued when controller for the service first starts. Version is also reported.

DHCP_DDNS_STARTING_TRANSACTION Request ID %1:

This is a debug message issued when DHCP-DDNS has begun a transaction for a given request.

DHCP_DDNS_STATE_MODEL_UNEXPECTED_ERROR Request ID %1: application encountered an unexpected error while carrying out a NameChangeRequest: %2

This is error message issued when the application fails to process a NameChangeRequest correctly. Some or all of the DNS updates requested as part of this update did not succeed. This is a programmatic error and should be reported.

DHCP_DDNS_TRANS_SEND_ERROR Request ID %1: application encountered an unexpected error while attempting to send a DNS update: %2

This is error message issued when the application is able to construct an update message but the attempt to send it suffered an unexpected error. This is most likely a programmatic error, rather than a communications issue. Some or all of the DNS updates requested as part of this request did not succeed.

DHCP_DDNS_UDP_SENDER_WATCH_SOCKET_CLOSE_ERROR watch socket failed to close: %1

This is an error message that indicates the application was unable to close the inbound or outbound side of a NCR sender's watch socket. While technically possible the error is highly unlikely to occur and should not impair the application's ability to process requests.

DHCP_DDNS_UNCAUGHT_NCR_RECV_HANDLER_ERROR unexpected exception thrown from the application receive completion handler: %1

This is an error message that indicates that an exception was thrown but not caught in the application's request receive completion handler. This is a programmatic error that needs to be reported. Dependent upon the nature of the error the application may or may not continue operating normally.

DHCP_DDNS_UNCAUGHT_NCR_SEND_HANDLER_ERROR unexpected exception thrown from the DHCP-DDNS client send completion handler: %1

This is an error message that indicates that an exception was thrown but not caught in the application's send completion handler. This is a programmatic error that needs to be reported. Dependent upon the nature of the error the client may or may not continue operating normally.

DHCP_DDNS_UNSUPPORTED_SIGNAL ignoring reception of unsupported signal: %1

This is a debug message indicating that the application received an unsupported signal. This is a programming error indicating that the application has registered to receive the signal but no associated processing logic has been added.

DHCP_DDNS_UPDATE_REQUEST_SENT Request ID %1: %2 to server: %3

This is a debug message issued when DHCP_DDNS sends a DNS request to a DNS server.

DHCP_DDNS_UPDATE_RESPONSE_RECEIVED Request ID %1: to server: %2 status: %3

This is a debug message issued when DHCP_DDNS receives sends a DNS update response from a DNS server.

EVAL Module

EVAL_DEBUG_AND Popping %1 and %2 pushing %3

This debug message indicates that two values are popped from the value stack. Then are then combined via logical and and the result is pushed onto the value stack.

EVAL_DEBUG_CONCAT Popping %1 and %2 pushing %3

This debug message indicates that the two strings are being popped off of the stack. They are then concatenated and the resulting string is pushed onto the stack. The strings are displayed in hex.

EVAL_DEBUG_EQUAL Popping %1 and %2 pushing result %3

This debug message indicates that the two strings are being popped off of the value stack and the result of comparing them is being pushed onto the value stack. The strings are displayed in hex.

EVAL_DEBUG_HEXSTRING Pushing hex string %1

This debug message indicates that the given binary string is being pushed onto the value stack. The string is displayed in hex.

EVAL_DEBUG_IPADDRESS Pushing IPAddress %1

This debug message indicates that the given binary string is being pushed onto the value stack. This represents either an IPv4 or IPv6 address. The string is displayed in hex.

EVAL_DEBUG_NOT Popping %1 pushing %2

This debug message indicates that the first value is popped from the value stack, negated and then pushed onto the value stack. The string is displayed in text.

EVAL_DEBUG_OPTION Pushing option %1 with value %2

This debug message indicates that the given string representing the value of the requested option is being pushed onto the value stack. The string may be the text or binary value of the string based on the representation type requested (.text or .hex) or "true" or "false" if the requested type is .exists. The option code may be for either an option or a sub-option as requested in the classification statement.

EVAL_DEBUG_OR Popping %1 and %2 pushing %3

This debug message indicates that two values are popped from the value stack. Then are then combined via logical or and the result is pushed onto the value stack. The string is displayed in text.

EVAL_DEBUG_PKT Pushing PKT meta data %1 with value %2

This debug message indicates that the given binary string representing the value of the requested meta data is being pushed onto the value stack. The string is displayed in hex at the exception of interface name.

EVAL_DEBUG_PKT4 Pushing PKT4 field %1 with value %2

This debug message indicates that the given binary string representing the value of the requested field is being pushed onto the value stack. The string is displayed in hex.

EVAL_DEBUG_PKT6 Pushing PKT6 field %1 with value %2

This debug message indicates that the given binary string representing the value of the requested field is being pushed onto the value stack. The string is displayed in hex.

EVAL_DEBUG_RELAY6 Pushing PKT6 relay field %1 nest %2 with value %3

This debug message indicates that the given binary string representing the value of the requested fied is being pushed onto the value stack. The string is displayed in hex.

EVAL_DEBUG_RELAY6_RANGE Pushing PKT6 relay field %1 nest %2 with value %3

This debug message is generated if the nest field is out of range. The empty string will always be the value pushed onto the stack.

EVAL_DEBUG_STRING Pushing text string %1

This debug message indicates that the given text string is being pushed onto the value stack. The string is displayed in text.

EVAL_DEBUG_SUBSTRING Popping length %1, start %2, string %3 pushing result %4

This debug message indicates that three values are being popped from the value stack and a result is being pushed onto the value stack. The values being popped are the starting point and length of a substring to extract from the given string. The resulting string is pushed onto the stack. The strings are displayed in hex.

EVAL_DEBUG_SUBSTRING_EMPTY Popping length %1, start %2, string %3 pushing result %4

This debug message indicates that the string popped from the stack was empty and so the result will also be empty. The start, length and string are still popped from the stack and the result is still pushed.

EVAL_DEBUG_SUBSTRING_RANGE Popping length %1, start %2, string %3 pushing result %4

This debug message indicates that the value of start is outside of the string and an empty result will be pushed onto the stack. The start, length and string are still popped from the stack and the result is still pushed. The strings are displayed in hex.

EVAL_DEBUG_VENDOR_CLASS_DATA Data %1 (out of %2 received) in vendor class found, pushing result '%3'

This debug message indicates that vendor class option was found and passed enterprise-id checks and has sufficient number of data chunks. The total number of chunks and value pushed are reported as debugging aid.

EVAL_DEBUG_VENDOR_CLASS_DATA_NOT_FOUND Requested data index %1, but option with enterprise-id %2 has only %3 data tuple(s), pushing result '%4'

This debug message indicates that vendor class option was found and passed enterprise-id checks, but does not have sufficient number of data chunks. Note that the index starts at 0, so there has to be at least (index + 1) data chunks.

EVAL_DEBUG_VENDOR_CLASS_ENTERPRISE_ID Pushing enterprise-id %1 as result 0x%2

This debug message indicates that the expression has been evaluated and vendor class option was found and its enterprise-id is being reported.

EVAL_DEBUG_VENDOR_CLASS_ENTERPRISE_ID_MISMATCH Was looking for %1, option had %2, pushing result '%3'

This debug message indicates that the expression has been evaluated and vendor class option was found, but has different enterprise-id than specified in the expression.

EVAL_DEBUG_VENDOR_CLASS_EXISTS Option with enterprise-id %1 found, pushing result '%2'

This debug message indicates that the expression has been evaluated and vendor class option was found.

EVAL_DEBUG_VENDOR_CLASS_NO_OPTION Option with code %1 missing, pushing result '%2'

This debug message indicates that the expression has been evaluated and vendor class option was not found.

EVAL_DEBUG_VENDOR_ENTERPRISE_ID Pushing enterprise-id %1 as result 0x%2

This debug message indicates that the expression has been evaluated and vendor option was found and its enterprise-id is being reported.

EVAL_DEBUG_VENDOR_ENTERPRISE_ID_MISMATCH Was looking for %1, option had %2, pushing result '%3'

This debug message indicates that the expression has been evaluated and vendor option was found, but has different enterprise-id than specified in the expression.

EVAL_DEBUG_VENDOR_EXISTS Option with enterprise-id %1 found, pushing result '%2'

This debug message indicates that the expression has been evaluated and vendor option was found.

EVAL_DEBUG_VENDOR_NO_OPTION Option with code %1 missing, pushing result '%2'

This debug message indicates that the expression has been evaluated and vendor option was not found.

EVAL_RESULT Expression %1 evaluated to %2

This debug message indicates that the expression has been evaluated to said value. This message is mostly useful during debugging of the client classification expressions.

HOOKS Module

HOOKS_ALL_CALLOUTS_DEREGISTERED hook library at index %1 removed all callouts on hook %2

A debug message issued when all callouts on the specified hook registered by the library with the given index were removed. This is similar to the HOOKS_CALLOUTS_REMOVED message (and the two are likely to be seen together), but is issued at a lower-level in the hook framework.

HOOKS_CALLOUTS_BEGIN begin all callouts for hook %1

This debug message is issued when callout manager begins to invoke callouts for the hook. The argument specifies the hook name.

HOOKS_CALLOUTS_COMPLETE completed callouts for hook %1 (total callouts duration: %2)

This debug message is issued when callout manager has completed execution of all callouts for the particular hook. The arguments specify the hook name and total execution time for all callouts in milliseconds.

HOOKS_CALLOUTS_REMOVED callouts removed from hook %1 for library %2

This is a debug message issued during library unloading. It notes that one of more callouts registered by that library have been removed from the specified hook. This is similar to the HOOKS_DEREGISTER_ALL_CALLOUTS message (and the two are likely to be seen together), but is issued at a higher-level in the hook framework.

HOOKS_CALLOUT_CALLED hooks library with index %1 has called a callout on hook %2 that has address %3 (callout duration: %4)

Only output at a high debugging level, this message indicates that a callout on the named hook registered by the library with the given index (in the list of loaded libraries) has been called and returned a success state. The address of the callout is given in the message. The message includes the callout execution time in milliseconds.

HOOKS_CALLOUT_DEREGISTERED hook library at index %1 deregistered a callout on hook %2

A debug message issued when all instances of a particular callouts on the hook identified in the message that were registered by the library with the given index have been removed.

HOOKS_CALLOUT_ERROR error returned by callout on hook %1 registered by library with index %2 (callout address %3) (callout duration %4)

If a callout returns an error status when called, this error message is issued. It identifies the hook to which the callout is attached, the index of the library (in the list of loaded libraries) that registered it and the address of the callout. The error is otherwise ignored. The error message includes the callout execution time in milliseconds.

HOOKS_CALLOUT_EXCEPTION exception thrown by callout on hook %1 registered by library with index %2 (callout address %3): %4 (callout duration: $5)

If a callout throws an exception when called, this error message is issued. It identifies the hook to which the callout is attached, the index of the library (in the list of loaded libraries) that registered it and the address of the callout. The error is otherwise ignored. The error message includes the callout execution time in milliseconds.

HOOKS_CALLOUT_REGISTRATION hooks library with index %1 registering callout for hook '%2'

This is a debug message, output when a library (whose index in the list of libraries (being) loaded is given) registers a callout.

HOOKS_CLOSE_ERROR failed to close hook library %1: %2

Kea has failed to close the named hook library for the stated reason. Although this is an error, this should not affect the running system other than as a loss of resources. If this error persists, you should restart Kea.

HOOKS_HOOK_LIST_RESET the list of hooks has been reset

This is a message indicating that the list of hooks has been reset. While this is usual when running the Kea test suite, it should not be seen when running Kea in a production environment. If this appears, please report a bug through the usual channels.

HOOKS_INCORRECT_VERSION hook library %1 is at version %2, require version %3

Kea has detected that the named hook library has been built against a version of Kea that is incompatible with the version of Kea running on your system. It has not loaded the library.

This is most likely due to the installation of a new version of Kea without rebuilding the hook library. A rebuild and re-install of the library should fix the problem in most cases.

HOOKS_LIBRARY_LOADED hooks library %1 successfully loaded

This information message is issued when a user-supplied hooks library has been successfully loaded.

HOOKS_LIBRARY_LOADING loading hooks library %1

This is a debug message output just before the specified library is loaded. If the action is successfully, it will be followed by the HOOKS_LIBRARY_LOADED informational message.

HOOKS_LIBRARY_UNLOADED hooks library %1 successfully unloaded

This information message is issued when a user-supplied hooks library has been successfully unloaded.

HOOKS_LIBRARY_UNLOADING unloading library %1

This is a debug message called when the specified library is being unloaded. If all is successful, it will be followed by the HOOKS_LIBRARY_UNLOADED informational message.

HOOKS_LIBRARY_VERSION hooks library %1 reports its version as %2

A debug message issued when the version check on the hooks library has succeeded.

HOOKS_LOAD_ERROR 'load' function in hook library %1 returned error %2

A "load" function was found in the library named in the message and was called. The function returned a non-zero status (also given in the message) which was interpreted as an error. The library has been unloaded and no callouts from it will be installed.

HOOKS_LOAD_EXCEPTION 'load' function in hook library %1 threw an exception

A "load" function was found in the library named in the message and was called. The function threw an exception (an error indication) during execution, which is an error condition. The library has been unloaded and no callouts from it will be installed.

HOOKS_LOAD_FRAMEWORK_EXCEPTION 'load' function in hook library %1 threw an exception: reason %2

A "load" function was found in the library named in the message and was called. Either the hooks framework or the function threw an exception (an error indication) during execution, which is an error condition; the cause of the exception is recorded in the message. The library has been unloaded and no callouts from it will be installed.

HOOKS_LOAD_SUCCESS 'load' function in hook library %1 returned success

This is a debug message issued when the "load" function has been found in a hook library and has been successfully called.

HOOKS_NO_LOAD no 'load' function found in hook library %1

This is a debug message saying that the specified library was loaded but no function called "load" was found in it. Providing the library contained some "standard" functions (i.e. functions with the names of the hooks for the given server), this is not an issue.

HOOKS_NO_UNLOAD no 'unload' function found in hook library %1

This is a debug message issued when the library is being unloaded. It merely states that the library did not contain an "unload" function.

HOOKS_NO_VERSION no 'version' function found in hook library %1

The shared library named in the message was found and successfully loaded, but Kea did not find a function named "version" in it. This function is required and should return the version of Kea against which the library was built. The value is used to check that the library was built against a compatible version of Kea. The library has not been loaded.

HOOKS_OPEN_ERROR failed to open hook library %1: %2

Kea failed to open the specified hook library for the stated reason. The library has not been loaded. Kea will continue to function, but without the services offered by the library.

HOOKS_STD_CALLOUT_REGISTERED hooks library %1 registered standard callout for hook %2 at address %3

This is a debug message, output when the library loading function has located a standard callout (a callout with the same name as a hook point) and registered it. The address of the callout is indicated.

HOOKS_UNLOAD_ERROR 'unload' function in hook library %1 returned error %2

During the unloading of a library, an "unload" function was found. It was called, but returned an error (non-zero) status, resulting in the issuing of this message. The unload process continued after this message and the library has been unloaded.

HOOKS_UNLOAD_EXCEPTION 'unload' function in hook library %1 threw an exception

During the unloading of a library, an "unload" function was found. It was called, but in the process generated an exception (an error indication). The unload process continued after this message and the library has been unloaded.

HOOKS_UNLOAD_FRAMEWORK_EXCEPTION 'unload' function in hook library %1 threw an exception, reason %2

During the unloading of a library, an "unload" function was found. It was called, but in the process either it or the hooks framework generated an exception (an error indication); the cause of the error is recorded in the message. The unload process continued after this message and the library has been unloaded.

HOOKS_UNLOAD_SUCCESS 'unload' function in hook library %1 returned success

This is a debug message issued when an "unload" function has been found in a hook library during the unload process, called, and returned success.

HOOKS_VERSION_EXCEPTION 'version' function in hook library %1 threw an exception

This error message is issued if the version() function in the specified hooks library was called and generated an exception. The library is considered unusable and will not be loaded.

HOSTS Module

HOSTS_CFG_ADD_HOST add the host for reservations: %1

This debug message is issued when new host (with reservations) is added to the server's configuration. The argument describes the host and its reservations in detail.

HOSTS_CFG_CLOSE_HOST_DATA_SOURCE Closing host data source: %1

This is a normal message being printed when the server closes host data source connection.

HOSTS_CFG_GET_ALL_ADDRESS4 get all hosts with reservations for IPv4 address %1

This debug message is issued when starting to retrieve all hosts, holding the reservation for the specific IPv4 address, from the configuration. The argument specifies the IPv4 address used to search the hosts.

HOSTS_CFG_GET_ALL_ADDRESS4_COUNT using address %1, found %2 host(s)

This debug message logs the number of hosts found using the specified IPv4 address. The arguments specify the IPv4 address used and the number of hosts found respectively.

HOSTS_CFG_GET_ALL_ADDRESS4_HOST using address %1 found host: %2

This debug message is issued when found host with the reservation for the specified IPv4 address. The arguments specify the IPv4 address and the detailed description of the host found.

HOSTS_CFG_GET_ALL_ADDRESS6 get all hosts with reservations for IPv6 address %1

This debug message is issued when starting to retrieve all hosts, holding the reservation for the specific IPv6 address, from the configuration. The argument specifies the IPv6 address used to search the hosts.

HOSTS_CFG_GET_ALL_ADDRESS6_COUNT using address %1, found %2 host(s)

This debug message logs the number of hosts found using the specified IPv6 address. The arguments specify the IPv6 address used and the number of hosts found respectively.

HOSTS_CFG_GET_ALL_ADDRESS6_HOST using address %1 found host: %2

This debug message is issued when found host with the reservation for the specified IPv6 address. The arguments specify the IPv6 address and the detailed description of the host found.

HOSTS_CFG_GET_ALL_HWADDR_DUID get all hosts with reservations for HWADDR %1 and DUID %2

This debug message is issued when starting to retrieve reservations for all hosts using specific HW address or DUID. The arguments specify the HW address and DUID respectively. The argument specify the HW address and DUID respectively.

HOSTS_CFG_GET_ALL_IDENTIFIER get all hosts with reservations using identifier: %1

This debug message is issued when starting to retrieve reservations for all hosts identified by HW address or DUID. The argument holds both the identifier type and the value.

HOSTS_CFG_GET_ALL_IDENTIFIER_COUNT using identifier %1, found %2 host(s)

This debug message logs the number of hosts found using the specified identifier. The arguments specify the identifier used and the number of hosts found respectively.

HOSTS_CFG_GET_ALL_IDENTIFIER_HOST using identifier: %1, found host: %2

This debug message is issued when found host identified by the specific identifier. The arguments specify the identifier and the detailed description of the host found.

HOSTS_CFG_GET_ALL_SUBNET_ID_ADDRESS6 get all hosts with reservations for subnet id %1 and IPv6 address %2

This debug message is issued when starting to retrieve all hosts connected to the specific subnet and having the specific IPv6 address reserved. The arguments specify subnet id and IPv6 address respectively.

HOSTS_CFG_GET_ALL_SUBNET_ID_ADDRESS6_COUNT using subnet id %1 and address %2, found %3 host(s)

This debug message include the details of the host found using the subnet id and address. The arguments specify subnet id, address and found host details respectively.

HOSTS_CFG_GET_ALL_SUBNET_ID_ADDRESS6_HOST using subnet id %1 and address %2, found host: %3

This debug message includes the details of the host found using the subnet id and address. The arguments specify subnet id, address and found host details respectively.

HOSTS_CFG_GET_ONE_PREFIX get one host with reservation for prefix %1/%2

This debug message is issued when starting to retrieve a host having a reservation for a specified prefix. The arguments specify a prefix and prefix length.

HOSTS_CFG_GET_ONE_PREFIX_HOST using prefix %1/%2, found host: %3

This debug message includes the details of the host found using the specific prefix/prefix length. The arguments specify prefix, prefix length and host details respectively.

HOSTS_CFG_GET_ONE_PREFIX_NULL host not found using prefix %1/%2

This debug messsage is issued when no host was found for a specified prefix and prefix length.

HOSTS_CFG_GET_ONE_SUBNET_ID_ADDRESS4 get one host with reservation for subnet id %1 and IPv4 address %2

This debug message is issued when starting to retrieve a host connected to the specific subnet and having the specific IPv4 address reserved. The arguments specify subnet id and IPv4 address respectively.

HOSTS_CFG_GET_ONE_SUBNET_ID_ADDRESS4_HOST using subnet id %1 and address %2, found host: %3

This debug message logs the details of the host found using the subnet id and IPv4 address.

HOSTS_CFG_GET_ONE_SUBNET_ID_ADDRESS4_NULL host not found using subnet id %1 and address %2

This debug message is issued when no host was found for the specified subnet id and IPv4 address.

HOSTS_CFG_GET_ONE_SUBNET_ID_ADDRESS6 get one host with reservation for subnet id %1 and including IPv6 address %2

This debug message is issued when starting to retrieve a host connected to the specific subnet and having the specific IPv6 address reserved. The arguments specify subnet id and IPv6 address respectively.

HOSTS_CFG_GET_ONE_SUBNET_ID_ADDRESS6_HOST using subnet id %1 and address %2, found host: %3

This debug message logs the details of the host found using the subnet id and IPv6 address.

HOSTS_CFG_GET_ONE_SUBNET_ID_ADDRESS6_NULL host not found using subnet id %1 and address %2

This debug message is issued when no host was found using the specified subnet if and IPv6 address.

HOSTS_CFG_GET_ONE_SUBNET_ID_IDENTIFIER get one host with %1 reservation for subnet id %2, identified by %3

This debug message is issued when starting to retrieve a host holding IPv4 or IPv6 reservations, which is connected to a specific subnet and is identified by a specific unique identifier. The first argument identifies if the IPv4 or IPv6 reservation is desired.

HOSTS_CFG_GET_ONE_SUBNET_ID_IDENTIFIER_HOST using subnet id %1 and identifier %2, found host: %3

This debug message includes the details of a host found using a subnet id and specific host identifier.

HOSTS_CFG_GET_ONE_SUBNET_ID_IDENTIFIER_NULL host not found using subnet id %1 and identifier %2

This debug message is issued when no host was found using the specified subnet id and host identifier.

HOSTS_MGR_ALTERNATE_GET4_SUBNET_ID_ADDRESS4 trying alternate source for host using subnet id %1 and address %2

This debug message is issued when the Host Manager doesn't find the host connected to the specific subnet and having the reservation for the specific IPv4 address, and it is starting to search for this host in the alternate host data source.

HOSTS_MGR_ALTERNATE_GET4_SUBNET_ID_HWADDR_DUID trying alternate source for host using subnet id %1, HWADDR %2, DUID%3

This debug message is issued when the Host Manager doesn't find the host connected to the specific subnet and identified by the HW address or DUID, and it is starting to search for this host in the alternate host data source.

HOSTS_MGR_ALTERNATE_GET6_PREFIX trying alternate source for host using prefix %1/%2

This debug message is issued when the Host Manager doesn't find the host connected to the specific subnet and having the reservation for the specified prefix, and it is starting to search for this host in the alternate host data source.

HOSTS_MGR_ALTERNATE_GET6_SUBNET_ID_ADDRESS6 trying alternate source for host using subnet id %1 and IPv6 address %2

This debug message is issued when the Host Manager doesn't find the host connected to the specific subnet and having the reservation for the specified IPv6 address, and it is starting to search for this host in the alternate host data source.

HOSTS_MGR_ALTERNATE_GET6_SUBNET_ID_DUID_HWADDR trying alternate source for host using subnet id %1, DUID %2, HWADDR %3

This debug message is issued when the Host Manager doesn't find the host connected to the specific subnet and identified by the specified DUID or HW Address, and it is starting to search for this host in the alternate host data source.

LFC Module

LFC_FAIL_PID_CREATE : %1

This message is issued if LFC detected a failure when trying to create the PID file. It includes a more specific error string.

LFC_FAIL_PID_DEL : %1

This message is issued if LFC detected a failure when trying to delete the PID file. It includes a more specific error string.

LFC_FAIL_PROCESS : %1

This message is issued if LFC detected a failure when trying to process the files. It includes a more specific error string.

LFC_FAIL_ROTATE : %1

This message is issued if LFC detected a failure when trying to rotate the files. It includes a more specific error string.

LFC_PROCESSING Previous file: %1, copy file: %2

This message is issued just before LFC starts processing the lease files.

LFC_READ_STATS Leases: %1, attempts: %2, errors: %3.

This message prints out the number of leases that were read, the number of attempts to read leases and the number of errors encountered while reading.

LFC_ROTATING LFC rotating files

This message is issued just before LFC starts rotating the lease files - removing the old and replacing them with the new.

LFC_RUNNING LFC instance already running

This message is issued if LFC detects that a previous copy of LFC may still be running via the PID check.

LFC_START Starting lease file cleanup

This message is issued as the LFC process starts.

LFC_TERMINATE LFC finished processing

This message is issued when the LFC process completes. It does not indicate that the process was successful only that it has finished.

LFC_WRITE_STATS Leases: %1, attempts: %2, errors: %3.

This message prints out the number of leases that were written, the number of attempts to write leases and the number of errors encountered while writing.

LOGIMPL Module

LOGIMPL_ABOVE_MAX_DEBUG debug level of %1 is too high and will be set to the maximum of %2

A message from the interface to the underlying logger implementation reporting that the debug level (as set by an internally-created string DEBUGn, where n is an integer, e.g. DEBUG22) is above the maximum allowed value and has been reduced to that value. The appearance of this message may indicate a programming error - please submit a bug report.

LOGIMPL_BAD_DEBUG_STRING debug string '%1' has invalid format

A message from the interface to the underlying logger implementation reporting that an internally-created string used to set the debug level is not of the correct format (it should be of the form DEBUGn, where n is an integer, e.g. DEBUG22). The appearance of this message indicates a programming error - please submit a bug report.

LOGIMPL_BELOW_MIN_DEBUG debug level of %1 is too low and will be set to the minimum of %2

A message from the interface to the underlying logger implementation reporting that the debug level (as set by an internally-created string DEBUGn, where n is an integer, e.g. DEBUG22) is below the minimum allowed value and has been increased to that value. The appearance of this message may indicate a programming error - please submit a bug report.

LOG Module

LOG_BAD_DESTINATION unrecognized log destination: %1

A logger destination value was given that was not recognized. The destination should be one of "console", "file", or "syslog".

LOG_BAD_SEVERITY unrecognized log severity: %1

A logger severity value was given that was not recognized. The severity should be one of "DEBUG", "INFO", "WARN", "ERROR", "FATAL" or "NONE".

LOG_BAD_STREAM bad log console output stream: %1

Logging has been configured so that output is written to the terminal (console) but the stream on which it is to be written is not recognized. Allowed values are "stdout" and "stderr".

LOG_DUPLICATE_MESSAGE_ID duplicate message ID (%1) in compiled code

During start-up, Kea detected that the given message identification had been defined multiple times in the Kea code. This indicates a programming error; please submit a bug report.

LOG_DUPLICATE_NAMESPACE line %1: duplicate $NAMESPACE directive found

When reading a message file, more than one $NAMESPACE directive was found. (This directive is used to set a C++ namespace when generating header files during software development.) Such a condition is regarded as an error and the read will be abandoned.

LOG_INPUT_OPEN_FAIL unable to open message file %1 for input: %2

The program was not able to open the specified input message file for the reason given.

LOG_INVALID_MESSAGE_ID line %1: invalid message identification '%2'

An invalid message identification (ID) has been found during the read of a message file. Message IDs should comprise only alphanumeric characters and the underscore, and should not start with a digit.

LOG_LOCK_TEST_MESSAGE this is a test message.

This is a log message used in testing.

LOG_NAMESPACE_EXTRA_ARGS line %1: $NAMESPACE directive has too many arguments

The $NAMESPACE directive in a message file takes a single argument, a namespace in which all the generated symbol names are placed. This error is generated when the compiler finds a $NAMESPACE directive with more than one argument.

LOG_NAMESPACE_INVALID_ARG line %1: $NAMESPACE directive has an invalid argument ('%2')

The $NAMESPACE argument in a message file should be a valid C++ namespace. This message is output if the simple check on the syntax of the string carried out by the reader fails.

LOG_NAMESPACE_NO_ARGS line %1: no arguments were given to the $NAMESPACE directive

The $NAMESPACE directive in a message file takes a single argument, a C++ namespace in which all the generated symbol names are placed. This error is generated when the compiler finds a $NAMESPACE directive with no arguments.

LOG_NO_MESSAGE_ID line %1: message definition line found without a message ID

Within a message file, message are defined by lines starting with a "%". The rest of the line should comprise the message ID and text describing the message. This error indicates the message compiler found a line in the message file comprising just the "%" and nothing else.

LOG_NO_MESSAGE_TEXT line %1: line found containing a message ID ('%2') and no text

Within a message file, message are defined by lines starting with a "%". The rest of the line should comprise the message ID and text describing the message. This error indicates the message compiler found a line in the message file comprising just the "%" and message identification, but no text.

LOG_NO_SUCH_MESSAGE could not replace message text for '%1': no such message

During start-up a local message file was read. A line with the listed message identification was found in the file, but the identification is not one contained in the compiled-in message dictionary. This message may appear a number of times in the file, once for every such unknown message identification.

There may be several reasons why this message may appear:

- The message ID has been mis-spelled in the local message file.

- The program outputting the message may not use that particular message (e.g. it originates in a module not used by the program).

- The local file was written for an earlier version of the Kea software and the later version no longer generates that message.

Whatever the reason, there is no impact on the operation of Kea.

LOG_OPEN_OUTPUT_FAIL unable to open %1 for output: %2

Originating within the logging code, the program was not able to open the specified output file for the reason given.

LOG_PREFIX_EXTRA_ARGS line %1: $PREFIX directive has too many arguments

Within a message file, the $PREFIX directive takes a single argument, a prefix to be added to the symbol names when a C++ file is created. This error is generated when the compiler finds a $PREFIX directive with more than one argument.

Note: the $PREFIX directive is deprecated and will be removed in a future version of Kea.

LOG_PREFIX_INVALID_ARG line %1: $PREFIX directive has an invalid argument ('%2')

Within a message file, the $PREFIX directive takes a single argument, a prefix to be added to the symbol names when a C++ file is created. As such, it must adhere to restrictions on C++ symbol names (e.g. may only contain alphanumeric characters or underscores, and may nor start with a digit). A $PREFIX directive was found with an argument (given in the message) that violates those restrictions.

Note: the $PREFIX directive is deprecated and will be removed in a future version of Kea.

LOG_READING_LOCAL_FILE reading local message file %1

This is an informational message output by Kea when it starts to read a local message file. (A local message file may replace the text of one or more messages; the ID of the message will not be changed though.)

LOG_READ_ERROR error reading from message file %1: %2

The specified error was encountered reading from the named message file.

LOG_UNRECOGNIZED_DIRECTIVE line %1: unrecognized directive '%2'

Within a message file, a line starting with a dollar symbol was found (indicating the presence of a directive) but the first word on the line (shown in the message) was not recognized.

LOG_WRITE_ERROR error writing to %1: %2

The specified error was encountered by the message compiler when writing to the named output file.

USER Module

USER_CHK_HOOK_LOAD_ERROR DHCP UserCheckHook could not be loaded: %1

This is an error message issued when the DHCP UserCheckHook could not be loaded. The exact cause should be explained in the log message. User subnet selection will revert to default processing.

USER_CHK_HOOK_UNLOAD_ERROR DHCP UserCheckHook an error occurred unloading the library: %1

This is an error message issued when an error occurs while unloading the UserCheckHook library. This is unlikely to occur and normal operations of the library will likely resume when it is next loaded.

USER_CHK_SUBNET4_SELECT_ERROR DHCP UserCheckHook an unexpected error occurred in subnet4_select callout: %1

This is an error message issued when the DHCP UserCheckHook subnet4_select hook encounters an unexpected error. The message should contain a more detailed explanation.

USER_CHK_SUBNET4_SELECT_REGISTRY_NULL DHCP UserCheckHook UserRegistry has not been created.

This is an error message issued when the DHCP UserCheckHook subnet4_select hook has been invoked but the UserRegistry has not been created. This is a programmatic error and should not occur.

USER_CHK_SUBNET6_SELECT_ERROR DHCP UserCheckHook an unexpected error occurred in subnet6_select callout: %1

This is an error message issued when the DHCP UserCheckHook subnet6_select hook encounters an unexpected error. The message should contain a more detailed explanation.

USER_CHK_SUBNET6_SELECT_REGISTRY_NULL DHCP UserCheckHook UserRegistry has not been created.

This is an error message issued when the DHCP UserCheckHook subnet6_select hook has been invoked but the UserRegistry has not been created. This is a programmatic error and should not occur.

kea-1.1.0/doc/guide/kea-guide.txt0000664000175000017500000205526312772742655013470 00000000000000 Kea Administrator Reference Manual This is the reference guide for Kea version 1.1.0. Copyright (c) 2010-2016 Internet Systems Consortium, Inc. Abstract Kea is an open source implementation of the Dynamic Host Configuration Protocol (DHCP) servers, developed and maintained by Internet Systems Consortium (ISC). This is the reference guide for Kea version 1.1.0. The most up-to-date version of this document (in PDF, HTML, and plain text formats), along with other documents for Kea, can be found at http://kea.isc.org/docs. -------------------------------------------------------------------------- Table of Contents 1. Introduction 1.1. Supported Platforms 1.2. Required Software at Run-time 1.3. Kea Software 2. Quick Start 2.1. Quick Start Guide for DHCPv4 and DHCPv6 Services 2.2. Running the Kea Servers Directly 3. Installation 3.1. Packages 3.2. Installation Hierarchy 3.3. Building Requirements 3.4. Installation from Source 3.4.1. Download Tar File 3.4.2. Retrieve from Git 3.4.3. Configure Before the Build 3.4.4. Build 3.4.5. Install 3.5. Selecting the Configuration Backend 3.6. DHCP Database Installation and Configuration 3.6.1. Building with MySQL Support 3.6.2. Building with PostgreSQL support 3.6.3. Building with CQL (Cassandra) support 4. Kea Database Administration 4.1. Databases and Database Version Numbers 4.2. The kea-admin Tool 4.3. Supported Databases 4.3.1. memfile 4.3.2. MySQL 4.3.3. PostgreSQL 4.3.4. CQL (Cassandra) 4.3.5. Using Read-Only Databases with Host Reservations 4.3.6. Limitations Related to the use of SQL Databases 5. Kea Configuration 5.1. JSON Configuration Backend 5.1.1. JSON Syntax 5.1.2. Simplified Notation 6. Managing Kea with keactrl 6.1. Overview 6.2. Command Line Options 6.3. The keactrl Configuration File 6.4. Commands 6.5. Overriding the Server Selection 7. The DHCPv4 Server 7.1. Starting and Stopping the DHCPv4 Server 7.2. DHCPv4 Server Configuration 7.2.1. Introduction 7.2.2. Lease Storage 7.2.3. Hosts Storage 7.2.4. Interface Configuration 7.2.5. Issues with Unicast Responses to DHCPINFORM 7.2.6. IPv4 Subnet Identifier 7.2.7. Configuration of IPv4 Address Pools 7.2.8. Standard DHCPv4 Options 7.2.9. Custom DHCPv4 options 7.2.10. DHCPv4 Vendor Specific Options 7.2.11. Nested DHCPv4 Options (Custom Option Spaces) 7.2.12. Unspecified Parameters for DHCPv4 Option Configuration 7.2.13. Stateless Configuration of DHCPv4 Clients 7.2.14. Client Classification in DHCPv4 7.2.15. DDNS for DHCPv4 7.2.16. Next Server (siaddr) 7.2.17. Echoing Client-ID (RFC 6842) 7.2.18. Using Client Identifier and Hardware Address 7.2.19. DHCPv4-over-DHCPv6: DHCPv4 Side 7.3. Host Reservation in DHCPv4 7.3.1. Address Reservation Types 7.3.2. Conflicts in DHCPv4 Reservations 7.3.3. Reserving a Hostname 7.3.4. Including Specific DHCPv4 Options in Reservations 7.3.5. Reserving Next Server, Server Hostname and Boot File Name 7.3.6. Reserving Client Classes in DHCPv4 7.3.7. Storing Host Reservations in MySQL or PostgreSQL 7.3.8. Storing host reservations in CQL (Cassandra) 7.3.9. Fine Tuning DHCPv4 Host Reservation 7.4. Server Identifier in DHCPv4 7.5. How the DHCPv4 Server Selects a Subnet for the Client 7.5.1. Using a Specific Relay Agent for a Subnet 7.5.2. Segregating IPv4 Clients in a Cable Network 7.6. Duplicate Addresses (DHCPDECLINE Support) 7.7. Statistics in the DHCPv4 Server 7.8. Management API for the DHCPv4 Server 7.9. Supported DHCP Standards 7.10. DHCPv4 Server Limitations 8. The DHCPv6 Server 8.1. Starting and Stopping the DHCPv6 Server 8.2. DHCPv6 Server Configuration 8.2.1. Introduction 8.2.2. Lease Storage 8.2.3. Hosts Storage 8.2.4. Interface Selection 8.2.5. IPv6 Subnet Identifier 8.2.6. Unicast Traffic Support 8.2.7. Subnet and Address Pool 8.2.8. Subnet and Prefix Delegation Pools 8.2.9. Standard DHCPv6 Options 8.2.10. Custom DHCPv6 Options 8.2.11. DHCPv6 Vendor-Specific Options 8.2.12. Nested DHCPv6 Options (Custom Option Spaces) 8.2.13. Unspecified Parameters for DHCPv6 Option Configuration 8.2.14. IPv6 Subnet Selection 8.2.15. Rapid Commit 8.2.16. DHCPv6 Relays 8.2.17. Relay-Supplied Options 8.2.18. Client Classification in DHCPv6 8.2.19. DDNS for DHCPv6 8.2.20. DHCPv4-over-DHCPv6: DHCPv6 Side 8.3. Host Reservation in DHCPv6 8.3.1. Address/Prefix Reservation Types 8.3.2. Conflicts in DHCPv6 Reservations 8.3.3. Reserving a Hostname 8.3.4. Including Specific DHCPv6 Options in Reservations 8.3.5. Reserving Client Classes in DHCPv6 8.3.6. Storing Host Reservations in MySQL or PostgreSQL 8.3.7. Storing Host Reservations in CQL (Cassandra) 8.3.8. Fine Tuning DHCPv6 Host Reservation 8.4. Server Identifier in DHCPv6 8.5. Stateless DHCPv6 (Information-Request Message) 8.6. Support for RFC 7550 8.7. Using Specific Relay Agent for a Subnet 8.8. Segregating IPv6 Clients in a Cable Network 8.9. MAC/Hardware Addresses in DHCPv6 8.10. Duplicate Addresses (DECLINE Support) 8.11. Statistics in the DHCPv6 Server 8.12. Management API for the DHCPv6 Server 8.13. Supported DHCPv6 Standards 8.14. DHCPv6 Server Limitations 9. Lease Expiration in DHCPv4 and DHCPv6 9.1. Lease Reclamation 9.2. Configuring Lease Reclamation 9.3. Configuring Lease Affinity 9.4. Default Configuration Values for Leases Reclamation 9.5. Reclaiming Expired Leases with Command 10. The DHCP-DDNS Server 10.1. Starting and Stopping the DHCP-DDNS Server 10.2. Configuring the DHCP-DDNS Server 10.2.1. Global Server Parameters 10.2.2. TSIG Key List 10.2.3. Forward DDNS 10.2.4. Reverse DDNS 10.2.5. Example DHCP-DDNS Server Configuration 10.3. DHCP-DDNS Server Limitations 11. The LFC process 11.1. Overview 11.2. Command Line Options 12. Client Classification 12.1. Client Classification Overview 12.2. Using Static Host Reservations In Classification 12.3. Using Vendor Class Information In Classification 12.4. Using Expressions In Classification 12.4.1. Logical operators 12.4.2. Substring 12.4.3. Concat 12.5. Configuring Classes 12.6. Configuring Subnets With Class Information 12.7. Using Classes 12.8. Classes and Hooks 12.9. Debugging Expressions 13. Hooks Libraries 13.1. Introduction 13.2. Configuring Hooks Libraries 13.3. Available Hooks Libraries 13.3.1. user_chk: Checking User Access 13.3.2. Forensic Logging Hooks 14. Statistics 14.1. Statistics Overview 14.2. Statistics Lifecycle 14.3. Commands for Manipulating Statistics 14.3.1. statistic-get command 14.3.2. statistic-reset command 14.3.3. statistic-remove command 14.3.4. statistic-get-all command 14.3.5. statistic-reset-all command 14.3.6. statistic-remove-all command 15. Management API 15.1. Data Syntax 15.2. Using the Control Channel 15.3. Commands Supported by Both the DHCPv4 and DHCPv6 Servers 15.3.1. leases-reclaim 15.3.2. list-commands 15.3.3. shutdown 16. The libdhcp++ Library 16.1. Interface detection and Socket handling 17. Logging 17.1. Logging Configuration 17.1.1. Loggers 17.1.2. Logging Message Format 17.1.3. Logging During Kea Startup 18. Frequently Asked Questions 18.1. General Frequently Asked Questions 18.1.1. Where did the Kea name came from? 18.1.2. Feature X is not supported yet. When/if will it be available? 18.2. Frequently Asked Questions about DHCPv4 18.2.1. I set up a firewall, but the Kea server still receives the traffic. Why? 18.3. Frequently Asked Questions about DHCPv6 18.3.1. Kea DHCPv6 doesn't seem to get incoming traffic. I checked with tcpdump (or other traffic capture software) that the incoming traffic is reaching the box. What's wrong? 19. Acknowledgments List of Tables 4.1. List of available backends 7.1. List of standard DHCPv4 options 7.2. List of standard DHCPv4 options (continued) 7.3. List of standard DHCP option types 7.4. Default FQDN Flag Behavior 7.5. DHCPv4 Statistics 8.1. List of Standard DHCPv6 Options 8.2. List of Experimental DHCPv6 Options 8.3. Default FQDN Flag Behavior 8.4. DHCPv6 Statistics 10.1. Our example network 10.2. Forward DDNS Domains Needed 10.3. Reverse DDNS Domains Needed 12.1. List of Classification Values 12.2. List of Classification Expressions 13.1. List of available hooks libraries Chapter 1. Introduction Table of Contents 1.1. Supported Platforms 1.2. Required Software at Run-time 1.3. Kea Software Kea is the next generation of DHCP software developed by ISC. It supports both DHCPv4 and DHCPv6 protocols along with their extensions, e.g. prefix delegation and dynamic updates to DNS. Kea was initially developed as a part of the BIND 10 framework. In early 2014, ISC made the decision to discontinue active development of BIND 10 and continue development of Kea as standalone DHCP software. This guide covers Kea version 1.1.0. 1.1. Supported Platforms Kea is officially supported on Red Hat Enterprise Linux, CentOS, Fedora and FreeBSD systems. It is also likely to work on many other platforms: Kea 1.1.0 builds have been tested on (in no particular order) Red Hat Enteprise Linux 6.4, Debian GNU/Linux 7, Ubuntu 12.04, Ubuntu 14.04, Ubuntu 16.04, Fedora Linux 19, Fedora 20, Fedora 22, CentOS Linux 7, NetBSD 6, FreeBSD 10.3, OpenBSD 5.7, OpenBSD 6.0, OS X 10.10, OS X 10.11. There are currently no plans to port Kea to Windows platforms. 1.2. Required Software at Run-time Running Kea uses various extra software which may not be provided in the default installation of some operating systems, nor in the standard package collections. You may need to install this required software separately. (For the build requirements, also see Section 3.3, "Building Requirements".) * Kea supports two cryptographic libraries: Botan and OpenSSL. Only one of them is required to be installed during compilation. If using Botan, Kea requires the Botan cryptographic library for C++ (http://botan.randombit.net/), version 1.8, 1.9 or 1.10. If OpenSSL is used, (http://www.openssl.org/), then Kea requires the OpenSSL C++ library version 1.0.*. Support for later versions of Botan and OpenSSL will be added in future releases of Kea. * Kea uses the log4cplus C++ logging library (http://log4cplus.sourceforge.net/). It requires log4cplus version 1.0.3 or later. * In order to store lease information in a MySQL database, Kea requires MySQL headers and libraries. This is an optional dependency in that Kea can be built without MySQL support. * In order to store lease information in a PostgreSQL database, Kea requires PostgreSQL headers and libraries. This is an optional dependency in that Kea can be built without PostgreSQL support. * In order to store lease information in a Cassandra database (CQL), Kea requires Cassandra headers and libraries. This is an optional dependency in that Kea can be built without Cassandra support. 1.3. Kea Software Kea is modular. Part of this modularity is accomplished using multiple cooperating processes which, together, provide the server functionality. The following software is included with Kea: * keactrl -- Tool to start, stop, reconfigure, and report status for the Kea servers. * kea-dhcp4 -- The DHCPv4 server process. This process responds to DHCPv4 queries from clients. * kea-dhcp6 -- The DHCPv6 server process. This process responds to DHCPv6 queries from clients. * kea-dhcp-ddns -- The DHCP Dynamic DNS process. This process acts as an intermediary between the DHCP servers and DNS servers. It receives name update requests from the DHCP servers and sends DNS Update messages to the DNS servers. * kea-admin -- A useful tool for database backend maintenance (creating a new database, checking versions, upgrading etc.) * kea-lfc -- This process removes redundant information from the files used to provide persistent storage for the memfile data base backend. While it can be run standalone, it is normally run as and when required by the Kea DHCP servers. * perfdhcp -- A DHCP benchmarking tool which simulates multiple clients to test both DHCPv4 and DHCPv6 server performance. The tools and modules are covered in full detail in this guide. In addition, manual pages are also provided in the default installation. Kea also provides C++ libraries and programmer interfaces for DHCP. These include detailed developer documentation and code examples. Chapter 2. Quick Start Table of Contents 2.1. Quick Start Guide for DHCPv4 and DHCPv6 Services 2.2. Running the Kea Servers Directly This section describes the basic steps needed to get Kea up and running. For further details, full customizations, and troubleshooting, see the respective chapters in the Kea guide. 2.1. Quick Start Guide for DHCPv4 and DHCPv6 Services 1. Install required run-time and build dependencies. See Section 3.3, "Building Requirements" for details. 2. Download Kea source tarball from ISC.org downloads page or ISC ftp server. 3. Extract the tarball. For example: $ tar xvzf kea-1.1.0.tar.gz 4. Go into the source directory and run the configure script: $ cd kea-1.1.0 $ ./configure [your extra parameters] 5. Build it: $ make 6. Install it (by default it will be placed in /usr/local/, so it is likely that you will need root privileges for this step): # make install 7. Edit the configuration file which by default is installed in [kea-install-dir]/etc/kea/kea.conf and contains configuration for all Kea services. Configuration choices for DHCPv4 and DHCPv6 services are described in Section 7.2, "DHCPv4 Server Configuration" and Section 8.2, "DHCPv6 Server Configuration":w respectively. 8. In order to start the DHCPv4 server in background, run the following command (as root): # keactrl start -s dhcp4 Or run the following command to start DHCPv6 server instead: # keactrl start -s dhcp6 Note that it is also possible to start both servers simultaneously: $ keactrl start 9. Verify that Kea server(s) are running: # keactrl status A server status of "inactive" may indicate a configuration error. Please check the log file (by default named [kea-install-dir]/var/kea/kea-dhcp4.log or [kea-install-dir]/var/kea/kea-dhcp6.log) for the details of the error. 10. If the server has been started successfully, test that it is responding to DHCP queries and that the client receives a configuration from the server; for example, use the ISC DHCP client. 11. Stop running the server(s): # keactrl stop For instructions specific to your system, please read the system specific notes, available on the Kea web site. The details of keactrl script usage can be found in Chapter 6, Managing Kea with keactrl. 2.2. Running the Kea Servers Directly The Kea servers can be started directly, without the need to use the keactrl. To start the DHCPv4 server run the following command: # kea-dhcp4 -c /path/to/your/kea4/config/file.json Similarly, to start the DHCPv6 server run the following command: # kea-dhcp6 -c /path/to/your/kea6/config/file.json Chapter 3. Installation Table of Contents 3.1. Packages 3.2. Installation Hierarchy 3.3. Building Requirements 3.4. Installation from Source 3.4.1. Download Tar File 3.4.2. Retrieve from Git 3.4.3. Configure Before the Build 3.4.4. Build 3.4.5. Install 3.5. Selecting the Configuration Backend 3.6. DHCP Database Installation and Configuration 3.6.1. Building with MySQL Support 3.6.2. Building with PostgreSQL support 3.6.3. Building with CQL (Cassandra) support 3.1. Packages Some operating systems or software package vendors may provide ready-to-use, pre-built software packages for Kea. Installing a pre-built package means you do not need to install the software required only to build Kea and do not need to make the software. FreeBSD ports, NetBSD pkgsrc, and Debian testing package collections provide all the prerequisite packages. 3.2. Installation Hierarchy The following is the directory layout of the complete Kea installation. (All directory paths are relative to the installation directory): * bin/ -- utility programs. * etc/kea/ -- configuration files. * include/ -- C++ development header files. * lib/ -- libraries. * sbin/ -- server software and commands used by the system administrator. * share/kea/ -- configuration specifications and examples. * share/doc/kea/ -- this guide, other supplementary documentation, and examples. * share/man/ -- manual pages (online documentation). * var/kea/ -- server identification, lease databases, and log files. 3.3. Building Requirements In addition to the run-time requirements (listed in Section 1.2, "Required Software at Run-time"), building Kea from source code requires various development include headers and program development tools. Note Some operating systems have split their distribution packages into a run-time and a development package. You will need to install the development package versions, which include header files and libraries, to build Kea from the source code. Building from source code requires the following software installed on the system: * Boost build-time headers (http://www.boost.org/). At least Boost version 1.41 is required. When header-only Boost error code is not available or wanted, the Boost system library is required too. * Botan (version 1.8, 1.9 or 1.10) or OpenSSL (versions 1.0.*). * log4cplus (at least version 1.0.3) development include headers. * A C++ compiler and standard development headers. Kea 1.1.0 builds have been tested with GCC g++ 4.2.1, 4.4.7, 4.6.3, 4.8.3, 4.8.4, 4.8.5, 5.4.0; Clang++ 3.4.1; and Apple Clang++ 703.0.31. * The development tools automake, libtool, pkg-config. * The MySQL client and the client development libraries, when using the --with-dhcp-mysql configuration flag to build the Kea MySQL database backend. In this case an instance of the MySQL server running locally or on a machine reachable over a network is required. Note that running the unit tests requires a local MySQL server. * The PostgreSQL client and the client development libraries, when using the --with-dhcp-pgsql configuration flag to build the Kea PostgreSQL database backend. In this case an instance of the PostgreSQL server running locally or on some other machine, reachable over the network from the machine running Kea, is required. Note that running the unit tests requires a local PostgreSQL server. * googletest (version 1.6 or later), when using the --with-gtest configuration option to build the unit tests. * The documentation generation tools elinks, docbook-xsl, libxslt and Doxygen, if using the --enable-generate-docs configuration option to create the documentation. Visit the user-contributed wiki at http://kea.isc.org/wiki/SystemSpecificNotes for system-specific installation tips. 3.4. Installation from Source Kea is open source software written in C++. It is freely available in source code form from ISC as a downloadable tar file. A copy of the Kea source code repository is accessible from Github (https://github.com/isc-projects/kea). Kea may also be available in pre-compiled ready-to-use packages from operating system vendors. 3.4.1. Download Tar File The Kea release tarballs may be downloaded from: http://ftp.isc.org/isc/kea/ (using FTP or HTTP). 3.4.2. Retrieve from Git Downloading this "bleeding edge" code is recommended only for developers or advanced users. Using development code in a production environment is not recommended. Note When building from source code retrieved via Git, additional software will be required: automake (v1.11 or later), libtoolize, and autoconf (v2.59 or later). These may need to be installed. The latest development code is available on Github (see https://github.com/isc-projects/kea). The Kea source is public and development is done in the "master" branch. The code can be checked out from https://github.com/isc-projects/kea.git: $ git clone https://github.com/isc-projects/kea.git The code checked out from the git repository does not include the generated configure script, Makefile.in files, nor their related build files. They can be created by running autoreconf with the --install switch. This will run autoconf, aclocal, libtoolize, autoheader, automake, and related commands. Write access to the Kea repository is only granted to ISC staff. If you are a developer planning to contribute to Kea, please fork our Github repository and use the "pull request" mechanism to request integration of your code. Please consult https://help.github.com/articles/fork-a-repo/ for help on how to fork a Github repository. The Kea Developer's Guide contains more information about the process, as well as describing the requirements for contributed code to be accepted by ISC. 3.4.3. Configure Before the Build Kea uses the GNU Build System to discover build environment details. To generate the makefiles using the defaults, simply run: $ ./configure Run ./configure with the --help switch to view the different options. Some commonly-used options are: --prefix Define the installation location (the default is /usr/local). --with-boost-include Define the path to find the Boost headers. --with-botan-config Specify the path to the botan-config script to build with Botan for cryptographic functions. --with-dhcp-mysql Build Kea with code to allow it to store leases (and access host reservations) in a MySQL database. --with-dhcp-pgsql Build Kea with code to allow it to store leases (and access host reservations) in a PostgreSQL database. --with-gtest-source Enable the building of the C++ Unit Tests using the Google Test framework. This option specifies the path to the gtest source. (If the framework is not installed on your system, it can be downloaded from https://code.google.com/p/googletest.) --with-log4cplus Define the path to find the Log4cplus headers and libraries. --with-openssl Replace Botan by the OpenSSL the cryptographic library. By default configure searches for a valid Botan installation: if one is not found, it searches for OpenSSL. Note For instructions concerning the installation and configuration of database backends for Kea, see Section 3.6, "DHCP Database Installation and Configuration". For information concerning the configuration backends, see Section 3.5, "Selecting the Configuration Backend". For example, the following command configures Kea to find the Boost headers in /usr/pkg/include, specifies that PostgreSQL support should be enabled, and sets the installation location to /opt/kea: $ ./configure \ --with-boost-include=/usr/pkg/include \ --with-dhcp-pgsql=/usr/local/bin/pg_config \ --prefix=/opt/kea If you have some problems with building Kea using the header-only Boost code or you'd like to use the Boost system library (assumed for the sake of this example to be located in /usr/pkg/lib): $ ./configure \ --with-boost-libs=-lboost_system \ --with-boost-lib-dir=/usr/pkg/lib If configure fails, it may be due to missing or old dependencies. If configure succeeds, it displays a report with the parameters used to build the code. This report is saved into the file config.report and is also embedded into the executable binaries, e.g., kea-dhcp4. 3.4.4. Build After the configure step is complete, build the executables from the C++ code and prepare the Python scripts by running the command: $ make 3.4.5. Install To install the Kea executables, support files, and documentation, issue the command: $ make install Do not use any form of parallel or job server options (such as GNU make's -j option) when performing this step: doing so may cause errors. Note The install step may require superuser privileges. If required, run ldconfig as root with /usr/local/lib (or with prefix/lib if configured with --prefix) in /etc/ld.so.conf (or the relevant linker cache configuration file for your OS): $ ldconfig Note If you do not run ldconfig where it is required, you may see errors like the following: program: error while loading shared libraries: libkea-something.so.1: cannot open shared object file: No such file or directory 3.5. Selecting the Configuration Backend Kea 0.9 introduced configuration backends that are switchable during the compilation phase. Only one backend, JSON, is currently supported. JSON JSON is the new default configuration backend that allows Kea to read JSON configuration files from disk. It does not require any framework and thus is considered more lightweight. It will allow dynamic on-line reconfiguration, but lacks remote capabilities (i.e. no RESTful API). 3.6. DHCP Database Installation and Configuration Kea stores its leases in a lease database. The software has been written in a way that makes it possible to choose which database product should be used to store the lease information. At present, Kea supports four database backends: MySQL, PostgreSQL, Cassandra and Memfile. To limit external dependencies, MySQL, PostgreSQL and Cassandra support are disabled by default and only Memfile is available. Support for the optional external database backend must be explicitly included when Kea is built. This section covers the building of Kea with one of the optional backends and the creation of the lease database. Note When unit tests are built with Kea (the --with-gtest configuration option is specified), the databases must be manually pre-configured for the unit tests to run. The details of this configuration can be found in the Kea Developer's Guide. 3.6.1. Building with MySQL Support Install MySQL according to the instructions for your system. The client development libraries must be installed. Build and install Kea as described in Chapter 3, Installation, with the following modification. To enable the MySQL database code, at the "configure" step (see Section 3.4.3, "Configure Before the Build"), the --with-dhcp-mysql switch should be specified: ./configure [other-options] --with-dhcp-mysql If MySQL was not installed in the default location, the location of the MySQL configuration program "mysql_config" should be included with the switch, i.e. ./configure [other-options] --with-dhcp-mysql=path-to-mysql_config See Section 4.3.2.1, "First Time Creation of the MySQL Database" for details regarding MySQL database configuration. 3.6.2. Building with PostgreSQL support Install PostgreSQL according to the instructions for your system. The client development libraries must be installed. Client development libraries are often packaged as "libpq". Build and install Kea as described in Chapter 3, Installation, with the following modification. To enable the PostgreSQL database code, at the "configure" step (see Section 3.4.3, "Configure Before the Build"), the --with-dhcp-pgsql switch should be specified: ./configure [other-options] --with-dhcp-pgsql If PostgreSQL was not installed in the default location, the location of the PostgreSQL configuration program "pg_config" should be included with the switch, i.e. ./configure [other-options] --with-dhcp-pgsql=path-to-pg_config See Section 4.3.3.1, "First Time Creation of the PostgreSQL Database" for details regarding PostgreSQL database configuration. 3.6.3. Building with CQL (Cassandra) support Install Cassandra according to the instructions for your system. The Cassandra project website contains useful pointers: http://cassandra.apache.org. Download and compile cpp-driver from DataStax. For details regarding dependencies for building cpp-driver, see the project homepage https://github.com/datastax/cpp-driver. In June 2016, the following commands were used: $ git clone https://github.com/datastax/cpp-driver $ cd cpp-driver $ mkdir build $ cmake .. $ make As of June 2016, cpp-driver does not include cql_config script yet. Work is in progress to contribute such a script to the cpp-driver project but, until that is complete, intermediate steps that need to be conducted. A cql_config script is present in the tools/ directory of the Kea sources. Before using it, please edit cql_config_defines.sh in the same directory and change the environment variable CPP_DRIVER_PATH to point to the directory, where cpp-driver sources are located. (If the cpp-driver sources already provide cql_config script please use that rather than the version from Kea sources.) Build and install Kea as described in Chapter 3, Installation, with the following modification. To enable the Cassandra (CQL) database code, at the "configure" step (see Section 3.4.3, "Configure Before the Build"), do: ./configure [other-options] --with-cql=path-to-cql_config Chapter 4. Kea Database Administration Table of Contents 4.1. Databases and Database Version Numbers 4.2. The kea-admin Tool 4.3. Supported Databases 4.3.1. memfile 4.3.2. MySQL 4.3.3. PostgreSQL 4.3.4. CQL (Cassandra) 4.3.5. Using Read-Only Databases with Host Reservations 4.3.6. Limitations Related to the use of SQL Databases 4.1. Databases and Database Version Numbers Kea supports storing leases and host reservations (i.e. static assignments of addresses, prefixes and options) in one of the several supported databases. As future versions of Kea are released, the structure of those databases will change. For example, Kea currently only stores lease information and host reservations. Future versions of Kea will store additional data such as subnet definitions: the database structure will need to be updated to accomdate the extra information. A given version of Kea expects a particular structure in the database and checks for this by examining the version of database it is using. Separate version numbers are maintained for backend databases, independent of the version of Kea itself. It is possible that the backend database version will stay the same through several Kea revisions: similarly, it is possible that the version of backend database may go up several revisions during a Kea upgrade. Versions for each database are independent, so an increment in the MySQL database version does not imply an increment in that of PostgreSQL. Backend versions are specified in a major.minor format. The minor number is increased when there are backward compatible changes introduced. For example, the addition of a new index. It is desirable, but not mandatory to apply such a change; you can run on older database version if you want to. (Although, in the example given, running without the new index may be at the expense of a performance penalty.) On the other hand, the major number is increased when an incompatible change is introduced, for example an extra column is added to a table. If you try to run Kea software on a database that is too old (as signified by mismatched backend major version number), Kea will refuse to run: administrative action will be required to upgrade the database. 4.2. The kea-admin Tool To manage the databases, Kea provides the kea-admin tool. It is able to initialize a new database, check its version number, perform a database upgrade, and dump lease data to a text file. kea-admin takes two mandatory parameters: command and backend. Additional, non-mandatory options may be specified. Currently supported commands are: * lease-init -- Initializes a new lease database. This is useful during a new Kea installation. The database is initialized to the latest version supported by the version of the software being installed. * lease-version -- Reports the lease database version number. This is not necessarily equal to the Kea version number as each backend has its own versioning scheme. * lease-upgrade -- Conducts a lease database upgrade. This is useful when upgrading Kea. * lease-dump -- Dumps the contents of the lease database (for MySQL, PostgreSQL or CQL backends) to a CSV (comma separated values) text file. The first line of the file contains the column names. This is meant to be used as a diagnostic tool, so it provides a portable, human-readable form of the lease data. backend specifies the backend type. Currently supported types are: * memfile -- Lease information is stored on disk in a text file. * mysql -- Lease information is stored in a MySQL relational database. * pgsql -- Lease information is stored in a PostgreSQL relational database. * cql -- Lease information is stored in a CQL database. Additional parameters may be needed, depending on your setup and specific operation: username, password and database name or the directory where specific files are located. See the appropriate manual page for details (man 8 kea-admin). 4.3. Supported Databases The following table presents the capabilities of available backends. Please refer to the specific sections dedicated to each backend to better understand their capabilities and limitations. Choosing the right backend may be essential for success or failure of your deployment. Table 4.1. List of available backends +------------------------------------------------------------------------+ | Feature | Memfile | MySQL | PostgreSQL | CQL(Cassandra) | |--------------------+----------+----------+------------+----------------| | Status | Stable | Stable | Stable | Experimental | |--------------------+----------+----------+------------+----------------| | Data format | CSV file | SQL RMDB | SQL RMDB | NoSQL database | | | | | | (CQL) | |--------------------+----------+----------+------------+----------------| | Leases | yes | yes | yes | yes | |--------------------+----------+----------+------------+----------------| | Host Reservations | no | yes | yes | no | |--------------------+----------+----------+------------+----------------| | Options defined on | no | yes | yes | no | | per host basis | | | | | +------------------------------------------------------------------------+ 4.3.1. memfile The memfile backend is able to store lease information, but is not able to store host reservation details: these must be stored in the configuration file. (There are no plans to add a host reservations storage capability to this backend.) No special initialization steps are necessary for the memfile backend. During the first run, both kea-dhcp4 and kea-dhcp6 will create an empty lease file if one is not present. Necessary disk write permission is required. 4.3.1.1. Upgrading Memfile Lease Files from an Earlier Version of Kea There are no special steps required to upgrade memfile lease files from an earlier version of Kea to a new version of Kea. During startup the servers will check the schema version of the lease files against their own. If there is a mismatch, the servers will automatically launch the LFC process to convert the files to the server's schema version. While this mechanism is primarily meant to ease the process of upgrading to newer versions of Kea, it can also be used for downgrading should the need arise. When upgrading, any values not present in the original lease files will be assigned appropriate default values. When downgrading, any data present in the files but not in the server's schema will be dropped. If you wish to convert the files manually, prior to starting the servers you may do so by running the LFC process yourself. See Chapter 11, The LFC process for more information. 4.3.2. MySQL MySQL is able to store leases, host reservations and options defined on a per host basis. This section can be safely ignored if you chose to store the data in other backends. 4.3.2.1. First Time Creation of the MySQL Database If you are setting the MySQL database for the first time, you need to create the database area within MySQL and set up the MySQL user ID under which Kea will access the database. This needs to be done manually: kea-admin is not able to do this for you. To create the database: 1. Log into MySQL as "root": $ mysql -u root -p Enter password: mysql> 2. Create the MySQL database: mysql> CREATE DATABASE database-name; (database-name is the name you have chosen for the database.) 3. Create the user under which Kea will access the database (and give it a password), then grant it access to the database tables: mysql> CREATE USER 'user-name'@'localhost' IDENTIFIED BY 'password'; mysql> GRANT ALL ON database-name.* TO 'user-name'@'localhost'; (user-name and password are the user ID and password you are using to allow Keas access to the MySQL instance. All apostrophes in the command lines above are required.) 4. At this point, you may elect to create the database tables. (Alternatively, you can exit MySQL and create the tables using the kea-admin tool, as explained below.) To do this: mysql> CONNECT database-name; mysql> SOURCE path-to-kea/share/kea/scripts/mysql/dhcpdb_create.mysql (path-to-kea is the location where you installed Kea.) 5. Exit MySQL: mysql> quit Bye $ If you elected not to create the tables in step 4, you can do so now by running the kea-admin tool: $ kea-admin lease-init mysql -u database-user -p database-password -n database-name (Do not do this if you did create the tables in step 4.) kea-admin implements rudimentary checks: it will refuse to initialize a database that contains any existing tables. If you want to start from scratch, you must remove all data manually. (This process is a manual operation on purpose to avoid possibly irretrievable mistakes by kea-admin.) 4.3.2.2. Upgrading a MySQL Database from an Earlier Version of Kea Sometimes a new Kea version may use newer database schema, so there will be a need to upgrade the existing database. This can be done using the kea-admin lease-upgrade command. To check the current version of the database, use the following command: $ kea-admin lease-version mysql -u database-user -p database-password -n database-name (See Section 4.1, "Databases and Database Version Numbers" for a discussion about versioning.) If the version does not match the minimum required for the new version of Kea (as described in the release notes), the database needs to be upgraded. Before upgrading, please make sure that the database is backed up. The upgrade process does not discard any data but, depending on the nature of the changes, it may be impossible to subsequently downgrade to an earlier version. To perform an upgrade, issue the following command: $ kea-admin lease-upgrade mysql -u database-user -p database-password -n database-name 4.3.3. PostgreSQL A PostgreSQL database must be set up if you want Kea to store lease and other information in PostgreSQL. This step can be safely ignored if you are using other database backends. 4.3.3.1. First Time Creation of the PostgreSQL Database The first task is to create both the lease database and the user under which the servers will access it. A number of steps are required: 1. Log into PostgreSQL as "root": $ sudo -u postgres psql postgres Enter password: postgres=# 2. Create the database: postgres=# CREATE DATABASE database-name; CREATE DATABASE postgres=# (database-name is the name you have chosen for the database.) 3. Create the user under which Kea will access the database (and give it a password), then grant it access to the database: postgres=# CREATE USER user-name WITH PASSWORD 'password'; CREATE ROLE postgres=# GRANT ALL PRIVILEGES ON DATABASE database-name TO user-name; GRANT postgres=# 4. Exit PostgreSQL: postgres=# \q Bye $ 5. At this point you are ready to create the database tables. This can be done using the kea-admin tool as explained in the next section (recommended), or manually. To create the tables manually enter the following command. Note that PostgreSQL will prompt you to enter the new user's password you specified in Step 3. When the command completes you will be returned to the shell prompt. You should see output similar to following: $ psql -d database-name -U user-name -f path-to-kea/share/kea/scripts/pgsql/dhcpdb_create.pgsql Password for user user-name: CREATE TABLE CREATE INDEX CREATE INDEX CREATE TABLE CREATE INDEX CREATE TABLE START TRANSACTION INSERT 0 1 INSERT 0 1 INSERT 0 1 COMMIT CREATE TABLE START TRANSACTION INSERT 0 1 COMMIT $ (path-to-kea is the location where you installed Kea.) If instead you encounter an error like: psql: FATAL: no pg_hba.conf entry for host "[local]", user "user-name", database "database-name", SSL off ... you will need to alter the PostgreSQL configuration. Kea uses password authentication when connecting to the database and must have the appropriate entries added to PostgreSQL's pg_hba.conf file. This file is normally located in the primary data directory for your PostgreSQL server. The precise path may vary but the default location for PostgreSQL 9.3 on Centos 6.5 is: /var/lib/pgsql/9.3/data/pg_hba.conf. Assuming Kea is running on the same host as PostgreSQL, adding lines similar to following should be sufficient to provide password-authenticated access to Kea's database: local database-name user-name password host database-name user-name 127.0.0.1/32 password host database-name user-name ::1/128 password These edits are primarily intended as a starting point not a definitive reference on PostgreSQL administration or database security. Please consult your PostgreSQL user manual before making these changes as they may expose other databases that you run. It may be necessary to restart PostgreSQL in order for these changes to take effect. 4.3.3.2. Initialize the PostgreSQL Database Using kea-admin If you elected not to create the tables manually, you can do so now by running the kea-admin tool: $ kea-admin lease-init pgsql -u database-user -p database-password -n database-name Do not do this if you already created the tables in manually. kea-admin implements rudimentary checks: it will refuse to initialize a database that contains any existing tables. If you want to start from scratch, you must remove all data manually. (This process is a manual operation on purpose to avoid possibly irretrievable mistakes by kea-admin.) 4.3.3.3. Upgrading a PostgreSQL Database from an Earlier Version of Kea The PostgreSQL database schema can be upgraded using the same tool and commands as described in Section 4.3.2.2, "Upgrading a MySQL Database from an Earlier Version of Kea", with the exception that the "pgsql" database backend type must be used in the commands. Use the following command to check the current schema version: $ kea-admin lease-version pgsql -u database-user -p database-password -n database-name Use the following command to perform an upgrade: $ kea-admin lease-upgrade pgsql -u database-user -p database-password -n database-name 4.3.4. CQL (Cassandra) Cassandra, or Cassandra Query Language (CQL), is the newest backend added to Kea. Since it was added recently and has not undergone as much testing as other backends, it is considered experimental: please use with caution. The CQL backend is currently able to store leases only. The ability to store host reservations will likely be added some time in the future. The CQL database must be properly set up if you want Kea to store information in CQL. This section can be safely ignored if you chose to store the data in other backends. 4.3.4.1. First Time Creation of the Cassandra Database If you are setting up the CQL database for the first time, you need to create the keyspace area within CQL. This needs to be done manually: kea-admin is not able to do this for you. To create the database: 1. Export CQLSH_HOST environemnt variable: $ export CQLSH_HOST=localhost 2. Log into CQL: $ cqlsh cql> 3. Create the CQL keyspace: cql> CREATE KEYSPACE keyspace-name WITH replication = {'class' : 'SimpleStrategy','replication_factor' : 1}; (keyspace-name is the name you have chosen for the keyspace) 4. At this point, you may elect to create the database tables. (Alternatively, you can exit CQL and create the tables using the kea-admin tool, as explained below) To do this: cqslh -k keyspace-name -f path-to-kea/share/kea/scripts/cql/dhcpdb_create.cql (path-to-kea is the location where you installed Kea) If you elected not to create the tables in step 4, you can do so now by running the kea-admin tool: $ kea-admin lease-init cql -n database-name (Do not do this if you did create the tables in step 4.) kea-admin implements rudimentary checks: it will refuse to initialize a database that contains any existing tables. If you want to start from scratch, you must remove all data manually. (This process is a manual operation on purpose to avoid possibly irretrievable mistakes by kea-admin) 4.3.4.2. Upgrading a CQL Database from an Earlier Version of Kea Sometimes a new Kea version may use newer database schema, so there will be a need to upgrade the existing database. This can be done using the kea-admin lease-upgrade command. To check the current version of the database, use the following command: $ kea-admin lease-version cql -n database-name (See Section 4.1, "Databases and Database Version Numbers" for a discussion about versioning) If the version does not match the minimum required for the new version of Kea (as described in the release notes), the database needs to be upgraded. Before upgrading, please make sure that the database is backed up. The upgrade process does not discard any data but, depending on the nature of the changes, it may be impossible to subsequently downgrade to an earlier version. To perform an upgrade, issue the following command: $ kea-admin lease-upgrade cql -n database-name 4.3.5. Using Read-Only Databases with Host Reservations If a read-only database is used for storing host reservations, Kea must be explicitly configured to operate on the database in read-only mode. Sections Section 7.2.3.2, "Using Read-Only Databases for Host Reservations" and Section 8.2.3.2, "Using Read-Only Databases for Host Reservations" describe when such configuration may be reqired and how to configure Kea to operate using a read-only host database. 4.3.6. Limitations Related to the use of SQL Databases The lease expiration time is stored in the SQL database for each lease as a timestamp value. Kea developers observed that MySQL database doesn't accept timestamps beyond 2147483647 seconds (maximum signed 32-bit number) from the beginning of the epoch. At the same time, some versions of PostgreSQL do accept greater values but the value is altered when it is read back. For this reason the lease database backends put the restriction for the maximum timestamp to be stored in the database, which is equal to the maximum signed 32-bit number. This effectively means that the current Kea version can't store the leases which expiration time is later than 2147483647 seconds since the beginning of the epoch (around year 2038). This will be fixed when the database support for longer timestamps is available. Chapter 5. Kea Configuration Table of Contents 5.1. JSON Configuration Backend 5.1.1. JSON Syntax 5.1.2. Simplified Notation Kea is designed to allow different methods by which it can be configured, each method being implemented by a component known as a configuration backend. At present, only one such backend is available, that allowing configuration by means of a JSON file. 5.1. JSON Configuration Backend JSON is the default configuration backend. It assumes that the servers are started from the command line (either directly or using a script, e.g. keactrl). The JSON backend uses certain signals to influence Kea. The configuration file is specified upon startup using the -c parameter. 5.1.1. JSON Syntax Configuration files for DHCPv4, DHCPv6 and DDNS modules are defined in an extended JSON format. Basic JSON is defined in RFC 4627. Kea components use a slightly modified form of JSON in that they allow shell-style comments in the file: lines with the hash (#) character in the first column are comment lines and are ignored. The configuration file consists of a single object (often colloquially called a map) started with a curly bracket. It comprises the "Dhcp4", "Dhcp6", "DhcpDdns" and/or "Logging" objects. It is possible to define additional elements, but they will be ignored. For example, it is possible to define Dhcp4, Dhcp6 and Logging elements in a single configuration file that can be used to start both the DHCPv4 and DHCPv6 components. When starting, the DHCPv4 component will use Dhcp4 object to configure itself and the Logging object to configure logging parameters; it will ignore the Dhcp6 object. A very simple configuration for both DHCPv4 and DHCPv6 could look like this: # The whole configuration starts here. { # DHCPv4 specific configuration starts here. "Dhcp4": { "interfaces-config": { "interfaces": [ "eth0" ], "dhcp-socket-type": "raw" }, "valid-lifetime": 4000, "renew-timer": 1000, "rebind-timer": 2000, "subnet4": [{ "pools": [ { "pool": "192.0.2.1-192.0.2.200" } ], "subnet": "192.0.2.0/24" }] }, # DHCPv4 specific configuration ends here. # DHCPv6 specific configuration starts here. "Dhcp6": { "interfaces-config": { "interfaces": [ "eth1" ] }, "preferred-lifetime": 3000, "valid-lifetime": 4000, "renew-timer": 1000, "rebind-timer": 2000, "subnet6": [{ "pools": [ { "pool": "2001:db8::/80" } ], "subnet": "2001:db8::/64" }] }, # DHCPv6 specific configuration ends here. # Logger parameters (that could be shared among several components) start here. # This section is used by both the DHCPv4 and DHCPv6 servers. "Logging": { "loggers": [{ "name": "*", "severity": "DEBUG" }] } # Logger parameters end here. # The whole configuration structure ends here. } More examples are available in the installed share/doc/kea/examples directory. To avoid repetition of mostly similar structures, examples in the rest of this guide will showcase only the subset of parameters appropriate for a given context. For example, when discussing the IPv6 subnets configuration in DHCPv6, only subnet6 parameters will be mentioned. It is implied that the remaining elements (the global map that holds Dhcp6, Logging and possibly DhcpDdns) are present, but they are omitted for clarity. Usually, locations where extra parameters may appear are denoted by an ellipsis. 5.1.2. Simplified Notation It is sometimes convenient to refer to a specific element in the configuration hierarchy. Each hierarchy level is separated by a slash. If there is an array, a specific instance within that array is referenced by a number in square brackets (with numbering starting at zero). For example, in the above configuration the valid-lifetime in the Dhcp6 component can be referred to as Dhcp6/valid-lifetime and the pool in the first subnet defined in the DHCPv6 configuration as Dhcp6/subnet6[0]/pool. Chapter 6. Managing Kea with keactrl Table of Contents 6.1. Overview 6.2. Command Line Options 6.3. The keactrl Configuration File 6.4. Commands 6.5. Overriding the Server Selection 6.1. Overview keactrl is a shell script which controls the startup, shutdown and reconfiguration of the Kea servers (kea-dhcp4, kea-dhcp6 and kea-dhcp-ddns). It also provides the means for checking the current status of the servers and determining the configuration files in use. 6.2. Command Line Options keactrl is run as follows: keactrl [-c keactrl-config-file] [-s server[,server,..]] is the one of the commands described in Section 6.4, "Commands". The optional -c keactrl-config-file switch allows specification of an alternate keactrl configuration file. (--ctrl-config is a synonym for -c.) In the absence of -c, keactrl will use the default configuration file [kea-install-dir]/etc/kea/keactrl.conf. The optional -s server[,server ...] switch selects the servers to which the command is issued. (--server is a synonym for -s.) If absent, the command is sent to all servers enabled in the keactrl configuration file. If multiple servers are specified, they should be separated by commas with no intervening spaces. 6.3. The keactrl Configuration File Depending on requirements, not all of the available servers need be run. The keactrl configuration file sets which servers are enabled and which are disabled. The default configuration file is [kea-install-dir]/etc/kea/keactrl.conf, but this can be overridden on a per-command basis using the -c switch. The contents of keactrl.conf are: # This is a configuration file for keactrl script which controls # the startup, shutdown, reconfiguration and gathering the status # of the Kea servers. # prefix holds the location where the Kea is installed. prefix=/usr/local # Location of Kea configuration file. kea_config_file=${prefix}/etc/kea/kea.conf # Location of Kea binaries. exec_prefix=${prefix} dhcp4_srv=${exec_prefix}/sbin/kea/kea-dhcp4 dhcp6_srv=${exec_prefix}/sbin/kea/kea-dhcp6 dhcp_ddns_srv=${exec_prefix}/sbin/kea/kea-dhcp-ddns # Start DHCPv4 server? dhcp4=yes # Start DHCPv6 server? dhcp6=yes # Start DHCP DDNS server? dhcp_ddns=yes # Be verbose? kea_verbose=no The dhcp4, dhcp6 and dhcp_ddns parameters set to "yes" configure keactrl to manage (start, reconfigure) all servers, i.e. kea-dhcp4, kea-dhcp6 and kea-dhcp-ddns. When any of these parameters is set to "no" the keactrl will ignore the corresponding server when starting or reconfiguring Kea. By default, Kea servers managed by keactrl are located in [kea-install-dir]/sbin. This should work for most installations. If the default location needs to be altered for any reason, the paths specified with the dhcp4_srv, dhcp6_srv and dhcp_ddns_srv parameters should be modified. The kea_verbose parameter specifies the verbosity of the servers being started. When kea_verbose is set to "yes" the logging level of the server is set to DEBUG. Modification of the logging severity in a configuration file, as described in Chapter 17, Logging, will have no effect as long as the kea_verbose is set to "yes". Setting it to "no" will cause the server to use the logging levels specified in the Kea configuration file for respective loggers. If no logging configuration is specified, the default settings will be used. Note The verbosity for the server is set when it is started. Once started, the verbosity can be only changed by stopping the server and starting it again with the new value of the kea_verbose parameter. 6.4. Commands The following commands are supported by keactrl: * start - starts selected servers. * stop - stops all running servers. * reload - triggers reconfiguration of the selected servers by sending the SIGHUP signal to them. * status - returns the status of the servers (active or inactive) and the names of the configuration files in use. Typical output from keactrl when starting the servers looks similar to the following: $ keactrl start INFO/keactrl: Starting kea-dhcp4 -c /usr/local/etc/kea/kea.conf -d INFO/keactrl: Starting kea-dhcp6 -c /usr/local/etc/kea/kea.conf -d INFO/keactrl: Starting kea-dhcp-ddns -c /usr/local/etc/kea/kea.conf -d Kea's servers create PID files upon startup. These files are used by keactrl to determine whether or not a given server is running. If one or more servers are running when the start command is issued, the output will look similar to the following: $ keactrl start INFO/keactrl: kea-dhcp4 appears to be running, see: PID 10918, PID file: /usr/local/var/kea/kea.kea-dhcp4.pid. INFO/keactrl: kea-dhcp6 appears to be running, see: PID 10924, PID file: /usr/local/var/kea/kea.kea-dhcp6.pid. INFO/keactrl: kea-dhcp-ddns appears to be running, see: PID 10930, PID file: /usr/local/var/kea/kea.kea-dhcp-ddns.pid. During normal shutdowns these PID files are deleted. They may, however, be left over as remnants following a system crash. It is possible, though highly unlikely, that upon system restart the PIDs they contain actually refer to processes unrelated to Kea. This condition will cause keactrl to decide that the servers are running, when in fact they are not. In such a case the PID files as listed in the keactrl output must be manually deleted. The following command stops all servers: $ keactrl stop INFO/keactrl: Stopping kea-dhcp4... INFO/keactrl: Stopping kea-dhcp6... INFO/keactrl: Stopping kea-dhcp-ddns... Note that the stop will attempt to stop all servers regardless of whether they are "enabled" in the keactrl.conf. If any of the servers are not running, an informational message is displayed as in the stop command output below. $ keactrl stop INFO/keactrl: kea-dhcp4 isn't running. INFO/keactrl: kea-dhcp6 isn't running. INFO/keactrl: kea-dhcp-ddns isn't running. As already mentioned, the reconfiguration of each Kea server is triggered by the SIGHUP signal. The reload command sends the SIGHUP signal to the servers that are enabled in the keactrl configuration file and are currently running. When a server receives the SIGHUP signal it re-reads its configuration file and, if the new configuration is valid, uses the new configuration. A reload is executed as follows: $ keactrl reload INFO/keactrl: Reloading kea-dhcp4... INFO/keactrl: Reloading kea-dhcp6... INFO/keactrl: Reloading kea-dhcp-ddns... If any of the servers are not running, an informational message is displayed as in the reload command output below. $ keactrl stop INFO/keactrl: kea-dhcp4 isn't running. INFO/keactrl: kea-dhcp6 isn't running. INFO/keactrl: kea-dhcp-ddns isn't running. Note Currently keactrl does not report configuration failures when the server is started or reconfigured. To check if the server's configuration succeeded the Kea log must be examined for errors. By default, this is written to the syslog file. Sometimes it is useful to check which servers are running. The status reports this, typical output looking like: $ keactrl status DHCPv4 server: active DHCPv6 server: inactive DHCP DDNS: active Kea configuration file: /usr/local/etc/kea/kea.conf keactrl configuration file: /usr/local/etc/kea/keactrl.conf 6.5. Overriding the Server Selection The optional -s switch allows the selection of the servers to which keactrl command is issued. For example, the following instructs keactrl to stop the kea-dhcp4 and kea-dhcp6 servers and leave the kea-dhcp-ddns server running: $ keactrl stop -s dhcp4,dhcp6 Similarly, the following will only start the kea-dhcp4 and kea-dhcp-ddns servers and not kea-dhcp6. $ keactrl start -s dhcp4,dhcp_ddns Note that the behavior of the -s switch with the start and reload commands is different to its behavior with the stop command. On start and reload, keactrl will check if the servers given as parameters to the -s switch are enabled in the keactrl configuration file: if not, the server will be ignored. For stop however, this check is not made: the command is applied to all listed servers, regardless of whether they have been enabled in the file. The following keywords can be used with the -s command line option: * dhcp4 for kea-dhcp4. * dhcp6 for kea-dhcp6. * dhcp_ddns for kea-dhcp-ddns. * all for all servers (default). Chapter 7. The DHCPv4 Server Table of Contents 7.1. Starting and Stopping the DHCPv4 Server 7.2. DHCPv4 Server Configuration 7.2.1. Introduction 7.2.2. Lease Storage 7.2.3. Hosts Storage 7.2.4. Interface Configuration 7.2.5. Issues with Unicast Responses to DHCPINFORM 7.2.6. IPv4 Subnet Identifier 7.2.7. Configuration of IPv4 Address Pools 7.2.8. Standard DHCPv4 Options 7.2.9. Custom DHCPv4 options 7.2.10. DHCPv4 Vendor Specific Options 7.2.11. Nested DHCPv4 Options (Custom Option Spaces) 7.2.12. Unspecified Parameters for DHCPv4 Option Configuration 7.2.13. Stateless Configuration of DHCPv4 Clients 7.2.14. Client Classification in DHCPv4 7.2.15. DDNS for DHCPv4 7.2.16. Next Server (siaddr) 7.2.17. Echoing Client-ID (RFC 6842) 7.2.18. Using Client Identifier and Hardware Address 7.2.19. DHCPv4-over-DHCPv6: DHCPv4 Side 7.3. Host Reservation in DHCPv4 7.3.1. Address Reservation Types 7.3.2. Conflicts in DHCPv4 Reservations 7.3.3. Reserving a Hostname 7.3.4. Including Specific DHCPv4 Options in Reservations 7.3.5. Reserving Next Server, Server Hostname and Boot File Name 7.3.6. Reserving Client Classes in DHCPv4 7.3.7. Storing Host Reservations in MySQL or PostgreSQL 7.3.8. Storing host reservations in CQL (Cassandra) 7.3.9. Fine Tuning DHCPv4 Host Reservation 7.4. Server Identifier in DHCPv4 7.5. How the DHCPv4 Server Selects a Subnet for the Client 7.5.1. Using a Specific Relay Agent for a Subnet 7.5.2. Segregating IPv4 Clients in a Cable Network 7.6. Duplicate Addresses (DHCPDECLINE Support) 7.7. Statistics in the DHCPv4 Server 7.8. Management API for the DHCPv4 Server 7.9. Supported DHCP Standards 7.10. DHCPv4 Server Limitations 7.1. Starting and Stopping the DHCPv4 Server It is recommended that the Kea DHCPv4 server be started and stopped using keactrl (described in Chapter 6, Managing Kea with keactrl). However, it is also possible to run the server directly: it accepts the following command-line switches: * -c file - specifies the configuration file. This is the only mandatory switch. * -d - specifies whether the server logging should be switched to debug/verbose mode. In verbose mode, the logging severity and debuglevel specified in the configuration file are ignored and "debug" severity and the maximum debuglevel (99) are assumed. The flag is convenient, for temporarily switching the server into maximum verbosity, e.g. when debugging. * -p port - specifies UDP port on which the server will listen. This is only useful during testing, as a DHCPv4 server listening on ports other than the standard ones will not be able to handle regular DHCPv4 queries. * -v - prints out the Kea version and exits. * -V - prints out the Kea extended version with additional parameters and exits. The listing includes the versions of the libraries dynamically linked to Kea. * -W - prints out the Kea configuration report and exits. The report is a copy of the config.report file produced by ./configure: it is embedded in the executable binary. The config.report may also be accessed more directly. The following command may be used to extract this information. The binary path may be found in the install directory or in the .libs subdirectory in the source tree. For example kea/src/bin/dhcp4/.libs/kea-dhcp4. strings path/kea-dhcp4 | sed -n 's/;;;; //p' On start-up, the server will detect available network interfaces and will attempt to open UDP sockets on all interfaces mentioned in the configuration file. Since the DHCPv4 server opens privileged ports, it requires root access. Make sure you run this daemon as root. During startup the server will attempt to create a PID file of the form: localstatedir]/[conf name].kea-dhcp6.pid where: * localstatedir: The value as passed into the build configure script. It defaults to "/usr/local/var". (Note that this value may be overridden at run time by setting the environment variable KEA_PIDFILE_DIR. This is intended primarily for testing purposes.) * conf name: The configuration file name used to start the server, minus all preceding path and file extension. For example, given a pathname of "/usr/local/etc/kea/myconf.txt", the portion used would be "myconf". If the file already exists and contains the PID of a live process, the server will issue a DHCP4_ALREADY_RUNNING log message and exit. It is possible, though unlikely, that the file is a remnant of a system crash and the process to which the PID belongs is unrelated to Kea. In such a case it would be necessary to manually delete the PID file. The server can be stopped using the kill command. When running in a console, the server can also be shut down by pressing ctrl-c. It detects the key combination and shuts down gracefully. 7.2. DHCPv4 Server Configuration 7.2.1. Introduction This section explains how to configure the DHCPv4 server using the Kea configuration backend. (Kea configuration using any other backends is outside of scope of this document.) Before DHCPv4 is started, its configuration file has to be created. The basic configuration is as follows: { # DHCPv4 configuration starts in this line "Dhcp4": { # First we set up global values "valid-lifetime": 4000, "renew-timer": 1000, "rebind-timer": 2000, # Next we setup the interfaces to be used by the server. "interfaces-config": { "interfaces": [ "eth0" ] }, # And we specify the type of lease database "lease-database": { "type": "memfile", "persist": true, "name": "/var/kea/dhcp4.leases" }, # Finally, we list the subnets from which we will be leasing addresses. "subnet4": [ { "subnet": "192.0.2.0/24", "pools": [ { "pool": "192.0.2.1 - 192.0.2.200" } ] } ] # DHCPv4 configuration ends with the next line } } The following paragraphs provide a brief overview of the parameters in the above example together with their format. Subsequent sections of this chapter go into much greater detail for these and other parameters. The lines starting with a hash (#) are comments and are ignored by the server; they do not impact its operation in any way. The configuration starts in the first line with the initial opening curly bracket (or brace). Each configuration consists of one or more objects. In this specific example, we have only one object, called Dhcp4. This is a simplified configuration, as usually there will be additional objects, like Logging or DhcpDns, but we omit them now for clarity. The Dhcp4 configuration starts with the "Dhcp4": { line and ends with the corresponding closing brace (in the above example, the brace after the last comment). Everything defined between those lines is considered to be the Dhcp4 configuration. In the general case, the order in which those parameters appear does not matter. There are two caveats here though. The first one is to remember that the configuration file must be well formed JSON. That means that the parameters for any given scope must be separated by a comma and there must not be a comma after the last parameter. When reordering a configuration file, keep in mind that moving a parameter to or from the last position in a given scope may also require moving the comma. The second caveat is that it is uncommon -- although legal JSON -- to repeat the same parameter multiple times. If that happens, the last occurrence of a given parameter in a given scope is used while all previous instances are ignored. This is unlikely to cause any confusion as there are no real life reasons to keep multiple copies of the same parameter in your configuration file. Moving onto the DHCPv4 configuration elements, the first few elements define some global parameters. valid-lifetime defines for how long the addresses (leases) given out by the server are valid. If nothing changes, a client that got an address is allowed to use it for 4000 seconds. (Note that integer numbers are specified as is, without any quotes around them.) renew-timer and rebind-timer are values (also in seconds) that define T1 and T2 timers that govern when the client will begin the renewal and rebind procedures. Note that renew-timer and rebind-timer are optional. If they are not specified the client will select values for T1 and T2 timers according to the RFC 2131. The interfaces-config map specifies the server configuration concerning the network interfaces, on which the server should listen to the DHCP messages. The interfaces parameter specifies a list of network interfaces on which the server should listen. Lists are opened and closed with square brackets, with elements separated by commas. Had we wanted to listen on two interfaces, the interfaces-config would look like this: "interfaces-config": { "interfaces": [ "eth0", "eth1" ] }, The next couple of lines define the lease database, the place where the server stores its lease information. This particular example tells the server to use memfile, which is the simplest (and fastest) database backend. It uses an in-memory database and stores leases on disk in a CSV file. This is a very simple configuration. Usually the lease database configuration is more extensive and contains additional parameters. Note that lease-database is an object and opens up a new scope, using an opening brace. Its parameters (just one in this example - type) follow. Had there been more than one, they would be separated by commas. This scope is closed with a closing brace. As more parameters for the Dhcp4 definition follow, a trailing comma is present. Finally, we need to define a list of IPv4 subnets. This is the most important DHCPv4 configuration structure as the server uses that information to process clients' requests. It defines all subnets from which the server is expected to receive DHCP requests. The subnets are specified with the subnet4 parameter. It is a list, so it starts and ends with square brackets. Each subnet definition in the list has several attributes associated with it, so it is a structure and is opened and closed with braces. At a minimum, a subnet definition has to have at least two parameters: subnet (that defines the whole subnet) and pools (which is a list of dynamically allocated pools that are governed by the DHCP server). The example contains a single subnet. Had more than one been defined, additional elements in the subnet4 parameter would be specified and separated by commas. For example, to define three subnets, the following syntax would be used: "subnet4": [ { "pools": [ { "pool": "192.0.2.1 - 192.0.2.200" } ], "subnet": "192.0.2.0/24" }, { "pools": [ { "pool": "192.0.3.100 - 192.0.3.200" } ], "subnet": "192.0.3.0/24" }, { "pools": [ { "pool": "192.0.4.1 - 192.0.4.254" } ], "subnet": "192.0.4.0/24" } ] Note that indentation is optional and is used for aesthetic purposes only. In some cases in may be preferable to use more compact notation. After all the parameters have been specified, we have two contexts open: global and Dhcp4, hence we need two closing curly brackets to close them. In a real life configuration file there most likely would be additional components defined such as Logging or DhcpDdns, so the closing brace would be followed by a comma and another object definition. 7.2.2. Lease Storage All leases issued by the server are stored in the lease database. Currently there are four database backends available: memfile (which is the default backend), MySQL, PostgreSQL and Cassandra. 7.2.2.1. Memfile - Basic Storage for Leases The server is able to store lease data in different repositories. Larger deployments may elect to store leases in a database. Section 7.2.2.2, "Lease Database Configuration" describes this option. In typical smaller deployments though, the server will store lease information in a CSV file rather than a database. As well as requiring less administration, an advantage of using a file for storage is that it eliminates a dependency on third-party database software. The configuration of the file backend (Memfile) is controlled through the Dhcp4/lease-database parameters. The type parameter is mandatory and it specifies which storage for leases the server should use. The value of "memfile" indicates that the file should be used as the storage. The following list gives additional, optional, parameters that can be used to configure the Memfile backend. * persist: controls whether the new leases and updates to existing leases are written to the file. It is strongly recommended that the value of this parameter is set to true at all times, during the server's normal operation. Not writing leases to disk will mean that if a server is restarted (e.g. after a power failure), it will not know what addresses have been assigned. As a result, it may hand out addresses to new clients that are already in use. The value of false is mostly useful for performance testing purposes. The default value of the persist parameter is true, which enables writing lease updates to the lease file. * name: specifies an absolute location of the lease file in which new leases and lease updates will be recorded. The default value for this parameter is "[kea-install-dir]/var/kea/kea-leases4.csv" . * lfc-interval: specifies the interval in seconds, at which the server will perform a lease file cleanup (LFC). This removes redundant (historical) information from the lease file and effectively reduces the lease file size. The cleanup process is described in more detailed fashion further in this section. The default value of the lfc-interval is 0, which disables the LFC. An example configuration of the Memfile backend is presented below: "Dhcp4": { "lease-database": { "type": "memfile", "persist": true, "name": "/tmp/kea-leases4.csv", "lfc-interval": 1800 } } This configuration selects the /tmp/kea-leases4.csv as the storage for lease information and enables persistence (writing lease updates to this file). It also configures the backend perform the periodic cleanup of the lease files, executed every 30 minutes. It is important to know how the lease file contents are organized to understand why the periodic lease file cleanup is needed. Every time the server updates a lease or creates a new lease for the client, the new lease information must be recorded in the lease file. For performance reasons, the server does not update the existing client's lease in the file, as it would potentially require rewriting the entire file. Instead, it simply appends the new lease information to the end of the file: the previous lease entries for the client are not removed. When the server loads leases from the lease file, e.g. at the server startup, it assumes that the latest lease entry for the client is the valid one. The previous entries are discarded. This means that the server can re-construct the accurate information about the leases even though there may be many lease entries for each client. However, storing many entries for each client results in bloated lease file and impairs the performance of the server's startup and reconfiguration as it needs to process a larger number of lease entries. Lease file cleanup (LFC) removes all previous entries for each client and leaves only the latest ones. The interval at which the cleanup is performed is configurable, and it should be selected according to the frequency of lease renewals initiated by the clients. The more frequent the renewals, the smaller the value of lfc-interval should be. Note however, that the LFC takes time and thus it is possible (although unlikely) that new cleanup is started while the previous cleanup instance is still running, if the lfc-interval is too short. The server would recover from this by skipping the new cleanup when it detects that the previous cleanup is still in progress. But it implies that the actual cleanups will be triggered more rarely than configured. Moreover, triggering a new cleanup adds an overhead to the server which will not be able to respond to new requests for a short period of time when the new cleanup process is spawned. Therefore, it is recommended that the lfc-interval value is selected in a way that would allow for the LFC to complete the cleanup before a new cleanup is triggered. Lease file cleanup is performed by a separate process (in background) to avoid a performance impact on the server process. In order to avoid the conflicts between two processes both using the same lease files, the LFC process operates on the copy of the original lease file, rather than on the lease file used by the server to record lease updates. There are also other files being created as a side effect of the lease file cleanup. The detailed description of the LFC is located on the Kea wiki: http://kea.isc.org/wiki/LFCDesign. 7.2.2.2. Lease Database Configuration Note Lease database access information must be configured for the DHCPv4 server, even if it has already been configured for the DHCPv6 server. The servers store their information independently, so each server can use a separate database or both servers can use the same database. Lease database configuration is controlled through the Dhcp4/lease-database parameters. The type of the database must be set to "memfile", "mysql", "postgresql" or "cql", e.g. "Dhcp4": { "lease-database": { "type": "mysql", ... }, ... } Next, the name of the database to hold the leases must be set: this is the name used when the database was created (see Section 4.3.2.1, "First Time Creation of the MySQL Database", Section 4.3.3.1, "First Time Creation of the PostgreSQL Database" or Section 4.3.4.1, "First Time Creation of the Cassandra Database"). "Dhcp4": { "lease-database": { "name": "database-name" , ... }, ... } If the database is located on a different system to the DHCPv4 server, the database host name must also be specified. (It should be noted that this configuration may have a severe impact on server performance.): "Dhcp4": { "lease-database": { "host": remote-host-name, ... }, ... } The usual state of affairs will be to have the database on the same machine as the DHCPv4 server. In this case, set the value to the empty string: "Dhcp4": { "lease-database": { "host" : "", ... }, ... } Should the database be located on a different system, you may need to specify a longer interval for the connection timeout: "Dhcp4": { "lease-database": { "connect-timeout" : timeout-in-seconds, ... }, ... } The default value of five seconds should be more than adequate for local connections. If a timeout is given though, it should be an integer greater than zero. Finally, the credentials of the account under which the server will access the database should be set: "Dhcp4": { "lease-database": { "user": "user-name", "password": "password", ... }, ... } If there is no password to the account, set the password to the empty string "". (This is also the default.) 7.2.3. Hosts Storage Kea is also able to store information about host reservations in the database. The hosts database configuration uses the same syntax as the lease database. In fact, a Kea server opens independent connections for each purpose, be it lease or hosts information. This arrangement gives the most flexibility. Kea can be used to keep leases and host reservations separately, but can also point to the same database. Currently the supported hosts database types are MySQL and PostgreSQL. The Cassandra backend does not support host reservations yet. Please note that usage of hosts storage is optional. A user can define all host reservations in the configuration file. That is the recommended way if the number of reservations is small. However, when the number of reservations grows it's more convenient to use host storage. Please note that both storage methods (configuration file and one of the supported databases) can be used together. If hosts are defined in both places, the definitions from the configuration file are checked first and external storage is checked later, if necessary. 7.2.3.1. DHCPv4 Hosts Database Configuration Hosts database configuration is controlled through the Dhcp4/hosts-database parameters. If enabled, the type of the database must be set to "mysql" or "postgresql". Other hosts backends may be added in later versions of Kea. "Dhcp4": { "hosts-database": { "type": "mysql", ... }, ... } Next, the name of the database to hold the reservations must be set: this is the name used when the lease database was created (see Section 4.3, "Supported Databases" for instructions how to setup the desired database type). "Dhcp4": { "hosts-database": { "name": "database-name" , ... }, ... } If the database is located on a different system than the DHCPv4 server, the database host name must also be specified. (Again it should be noted that this configuration may have a severe impact on server performance.): "Dhcp4": { "hosts-database": { "host": remote-host-name, ... }, ... } The usual state of affairs will be to have the database on the same machine as the DHCPv4 server. In this case, set the value to the empty string: "Dhcp4": { "hosts-database": { "host" : "", ... }, ... } Finally, the credentials of the account under which the server will access the database should be set: "Dhcp4": { "hosts-database": { "user": "user-name", "password": "password", ... }, ... } If there is no password to the account, set the password to the empty string "". (This is also the default.) 7.2.3.2. Using Read-Only Databases for Host Reservations In some deployments the database user whose name is specified in the database backend configuration may not have write privileges to the database. This is often required by the policy within a given network to secure the data from being unintentionally modified. In many cases administrators have inventory databases deployed, which contain substantially more information about the hosts than static reservations assigned to them. The inventory database can be used to create a view of a Kea hosts database and such view is often read only. Kea host database backends operate with an implicit configuration to both read from and write to the database. If the database user does not have write access to the host database, the backend will fail to start and the server will refuse to start (or reconfigure). However, if access to a read only host database is required for retrieving reservations for clients and/or assign specific addresses and options, it is possible to explicitly configure Kea to start in "read-only" mode. This is controlled by the readonly boolean parameter as follows: "Dhcp4": { "hosts-database": { "readonly": true, ... }, ... } Setting this parameter to false would configure the database backend to operate in "read-write" mode, which is also a default configuration if the parameter is not specified. Note The readonly parameter is currently only supported for MySQL and PostgreSQL databases. 7.2.4. Interface Configuration The DHCPv4 server has to be configured to listen on specific network interfaces. The simplest network interface configuration tells the server to listen on all available interfaces: "Dhcp4": { "interfaces-config": { "interfaces": [ "*" ] } ... }, The asterisk plays the role of a wildcard and means "listen on all interfaces". However, it is usually a good idea to explicitly specify interface names: "Dhcp4": { "interfaces-config": { "interfaces": [ "eth1", "eth3" ] }, ... } It is possible to use wildcard interface name (asterisk) concurrently with explicit interface names: "Dhcp4": { "interfaces-config": { "interfaces": [ "eth1", "eth3", "*" ] }, ... } It is anticipated that this form of usage will only be used when it is desired to temporarily override a list of interface names and listen on all interfaces. Some deployments of DHCP servers require that the servers listen on the interfaces with multiple IPv4 addresses configured. In these situations, the address to use can be selected by appending an IPv4 address to the interface name in the following manner: "Dhcp4": { "interfaces-config": { "interfaces": [ "eth1/10.0.0.1", "eth3/192.0.2.3" ] }, ... } Should the server be required to listen on multiple IPv4 addresses assigned to the same interface, multiple addresses can be specified for an interface as in the example below: "Dhcp4": { "interfaces-config": { "interfaces": [ "eth1/10.0.0.1", "eth1/10.0.0.2" ] }, ... } Alternatively, if the server should listen on all addresses for the particular interface, an interface name without any address should be specified. Kea supports responding to directly connected clients which don't have an address configured. This requires that the server injects the hardware address of the destination into the data link layer of the packet being sent to the client. The DHCPv4 server utilizes the raw sockets to achieve this, and builds the entire IP/UDP stack for the outgoing packets. The down side of raw socket use, however, is that incoming and outgoing packets bypass the firewalls (e.g. iptables). It is also troublesome to handle traffic on multiple IPv4 addresses assigned to the same interface, as raw sockets are bound to the interface and advanced packet filtering techniques (e.g. using the BPF) have to be used to receive unicast traffic on the desired addresses assigned to the interface, rather than capturing whole traffic reaching the interface to which the raw socket is bound. Therefore, in the deployments where the server doesn't have to provision the directly connected clients and only receives the unicast packets from the relay agents, the DHCP server should be configured to utilize IP/UDP datagram sockets instead of raw sockets. The following configuration demonstrates how this can be achieved: "Dhcp4": { "interfaces-config": { "interfaces": [ "eth1", "eth3" ], "dhcp-socket-type": "udp" }, ... } The dhcp-socket-type specifies that the IP/UDP sockets will be opened on all interfaces on which the server listens, i.e. "eth1" and "eth3" in our case. If the dhcp-socket-type is set to raw, it configures the server to use raw sockets instead. If the dhcp-socket-type value is not specified, the default value raw is used. Using UDP sockets automatically disables the reception of broadcast packets from directly connected clients. This effectively means that the UDP sockets can be used for relayed traffic only. When using the raw sockets, both the traffic from the directly connected clients and the relayed traffic will be handled. Caution should be taken when configuring the server to open multiple raw sockets on the interface with several IPv4 addresses assigned. If the directly connected client sends the message to the broadcast address all sockets on this link will receive this message and multiple responses will be sent to the client. Hence, the configuration with multiple IPv4 addresses assigned to the interface should not be used when the directly connected clients are operating on that link. To use a single address on such interface, the "interface-name/address" notation should be used. Note Specifying the value raw as the socket type, doesn't guarantee that the raw sockets will be used! The use of raw sockets to handle the traffic from the directly connected clients is currently supported on Linux and BSD systems only. If the raw sockets are not supported on the particular OS, the server will issue a warning and fall back to use IP/UDP sockets. 7.2.5. Issues with Unicast Responses to DHCPINFORM The use of UDP sockets has certain benefits in deployments where the server receives only relayed traffic; these benefits are mentioned in Section 7.2.4, "Interface Configuration". From the administrator's perspective it is often desirable to configure the system's firewall to filter out the unwanted traffic, and the use of UDP sockets facilitates this. However, the administrator must also be aware of the implications related to filtering certain types of traffic as it may impair the DHCP server's operation. In this section we are focusing on the case when the server receives the DHCPINFORM message from the client via a relay. According to RFC 2131, the server should unicast the DHCPACK response to the address carried in the "ciaddr" field. When the UDP socket is in use, the DHCP server relies on the low level functions of an operating system to build the data link, IP and UDP layers of the outgoing message. Typically, the OS will first use ARP to obtain the client's link layer address to be inserted into the frame's header, if the address is not cached from a previous transaction that the client had with the server. When the ARP exchange is successful, the DHCP message can be unicast to the client, using the obtained address. Some system administrators block ARP messages in their network, which causes issues for the server when it responds to the DHCPINFORM messages, because the server is unable to send the DHCPACK if the preceding ARP communication fails. Since the OS is entirely responsible for the ARP communication and then sending the DHCP packet over the wire, the DHCP server has no means to determine that the ARP exchange failed and the DHCP response message was dropped. Thus, the server does not log any error messages when the outgoing DHCP response is dropped. At the same time, all hooks pertaining to the packet sending operation will be called, even though the message never reaches its destination. Note that the issue described in this section is not observed when the raw sockets are in use, because, in this case, the DHCP server builds all the layers of the outgoing message on its own and does not use ARP. Instead, it inserts the value carried in the 'chaddr' field of the DHCPINFORM message into the link layer. Server administrators willing to support DHCPINFORM messages via relays should not block ARP traffic in their networks or should use raw sockets instead of UDP sockets. 7.2.6. IPv4 Subnet Identifier The subnet identifier is a unique number associated with a particular subnet. In principle, it is used to associate clients' leases with their respective subnets. When a subnet identifier is not specified for a subnet being configured, it will be automatically assigned by the configuration mechanism. The identifiers are assigned from 1 and are monotonically increased for each subsequent subnet: 1, 2, 3 .... If there are multiple subnets configured with auto-generated identifiers and one of them is removed, the subnet identifiers may be renumbered. For example: if there are four subnets and the third is removed the last subnet will be assigned the identifier that the third subnet had before removal. As a result, the leases stored in the lease database for subnet 3 are now associated with subnet 4, something that may have unexpected consequences. It is planned to implement a mechanism to preserve auto-generated subnet ids in a future version of Kea. However, the only remedy for this issue at present is to manually specify a unique identifier for each subnet. The following configuration will assign the specified subnet identifier to the newly configured subnet: "Dhcp4": { "subnet4": [ { "subnet": "192.0.2.0/24", "id": 1024, ... } ] } This identifier will not change for this subnet unless the "id" parameter is removed or set to 0. The value of 0 forces auto-generation of the subnet identifier. 7.2.7. Configuration of IPv4 Address Pools The main role of a DHCPv4 server is address assignment. For this, the server has to be configured with at least one subnet and one pool of dynamic addresses for it to manage. For example, assume that the server is connected to a network segment that uses the 192.0.2.0/24 prefix. The Administrator of that network has decided that addresses from range 192.0.2.10 to 192.0.2.20 are going to be managed by the Dhcp4 server. Such a configuration can be achieved in the following way: "Dhcp4": { "subnet4": [ { "subnet": "192.0.2.0/24", "pools": [ { "pool": "192.0.2.10 - 192.0.2.20" } ], ... } ] } Note that subnet is defined as a simple string, but the pools parameter is actually a list of pools: for this reason, the pool definition is enclosed in square brackets, even though only one range of addresses is specified. Each pool is a structure that contains the parameters that describe a single pool. Currently there is only one parameter, pool, which gives the range of addresses in the pool. Additional parameters will be added in future releases of Kea. It is possible to define more than one pool in a subnet: continuing the previous example, further assume that 192.0.2.64/26 should be also be managed by the server. It could be written as 192.0.2.64 to 192.0.2.127. Alternatively, it can be expressed more simply as 192.0.2.64/26. Both formats are supported by Dhcp4 and can be mixed in the pool list. For example, one could define the following pools: "Dhcp4": { "subnet4": [ { "subnet": "192.0.2.0/24", "pools": [ { "pool": "192.0.2.10-192.0.2.20" }, { "pool": "192.0.2.64/26" } ], ... } ], ... } White space in pool definitions is ignored, so spaces before and after the hyphen are optional. They can be used to improve readability. The number of pools is not limited, but for performance reasons it is recommended to use as few as possible. The server may be configured to serve more than one subnet: "Dhcp4": { "subnet4": [ { "subnet": "192.0.2.0/24", "pools": [ { "pool": "192.0.2.1 - 192.0.2.200" } ], ... }, { "subnet": "192.0.3.0/24", "pools": [ { "pool": "192.0.3.100 - 192.0.3.200" } ], ... }, { "subnet": "192.0.4.0/24", "pools": [ { "pool": "192.0.4.1 - 192.0.4.254" } ], ... } ] } When configuring a DHCPv4 server using prefix/length notation, please pay attention to the boundary values. When specifying that the server can use a given pool, it will also be able to allocate the first (typically network address) and the last (typically broadcast address) address from that pool. In the aforementioned example of pool 192.0.3.0/24, both 192.0.3.0 and 192.0.3.255 addresses may be assigned as well. This may be invalid in some network configurations. If you want to avoid this, please use the "min-max" notation. 7.2.8. Standard DHCPv4 Options One of the major features of the DHCPv4 server is to provide configuration options to clients. Most of the options are sent by the server only if the client explicitly requests them using the Parameter Request List option. Those that do not require inclusion in the Parameter Request List option are commonly used options, e.g. "Domain Server", and options which require special behavior, e.g. "Client FQDN" is returned to the client if the client has included this option in its message to the server. Table 7.1, "List of standard DHCPv4 options" comprises the list of the standard DHCPv4 options whose values can be configured using the configuration structures described in this section. This table excludes the options which require special processing and thus cannot be configured with some fixed values. The last column of the table indicates which options can be sent by the server even when they are not requested in the Parameter Request list option, and those which are sent only when explicitly requested. The following example shows how to configure the addresses of DNS servers, which is one of the most frequently used options. Options specified in this way are considered global and apply to all configured subnets. "Dhcp4": { "option-data": [ { "name": "domain-name-servers", "code": 6, "space": "dhcp4", "csv-format": true, "data": "192.0.2.1, 192.0.2.2" }, ... ] } The name parameter specifies the option name. For a list of currently supported names, see Table 7.1, "List of standard DHCPv4 options" below. The code parameter specifies the option code, which must match one of the values from that list. The next line specifies the option space, which must always be set to "dhcp4" as these are standard DHCPv4 options. For other option spaces, including custom option spaces, see Section 7.2.11, "Nested DHCPv4 Options (Custom Option Spaces)". The next line specifies the format in which the data will be entered: use of CSV (comma separated values) is recommended. The sixth line gives the actual value to be sent to clients. Data is specified as normal text, with values separated by commas if more than one value is allowed. Options can also be configured as hexadecimal values. If csv-format is set to false, option data must be specified as a hexadecimal string. The following commands configure the domain-name-servers option for all subnets with the following addresses: 192.0.3.1 and 192.0.3.2. Note that csv-format is set to false. "Dhcp4": { "option-data": [ { "name": "domain-name-servers", "code": 6, "space": "dhcp4", "csv-format": false, "data": "C0 00 03 01 C0 00 03 02" }, ... ], ... } Most of the parameters in the "option-data" structure are optional and can be omitted in some circumstances as discussed in the Section 7.2.12, "Unspecified Parameters for DHCPv4 Option Configuration". It is possible to specify or override options on a per-subnet basis. If clients connected to most of your subnets are expected to get the same values of a given option, you should use global options: you can then override specific values for a small number of subnets. On the other hand, if you use different values in each subnet, it does not make sense to specify global option values (Dhcp4/option-data), rather you should set only subnet-specific values (Dhcp4/subnet[X]/option-data[Y]). The following commands override the global DNS servers option for a particular subnet, setting a single DNS server with address 192.0.2.3. "Dhcp4": { "subnet4": [ { "option-data": [ { "name": "domain-name-servers", "code": 6, "space": "dhcp4", "csv-format": true, "data": "192.0.2.3" }, ... ], ... }, ... ], ... } The currently supported standard DHCPv4 options are listed in Table 7.1, "List of standard DHCPv4 options" and Table 7.2, "List of standard DHCPv4 options (continued)". The "Name" and "Code" are the values that should be used as a name in the option-data structures. "Type" designates the format of the data: the meanings of the various types is given in Table 7.3, "List of standard DHCP option types". Some options are designated as arrays, which means that more than one value is allowed in such an option. For example the option time-servers allows the specification of more than one IPv4 address, so allowing clients to obtain the addresses of multiple NTP servers. The Section 7.2.9, "Custom DHCPv4 options" describes the configuration syntax to create custom option definitions (formats). It is generally not allowed to create custom definitions for standard options, even if the definition being created matches the actual option format defined in the RFCs. There is an exception from this rule for standard options for which Kea currently does not provide a definition. In order to use such options, a server administrator must create a definition as described in Section 7.2.9, "Custom DHCPv4 options" in the 'dhcp4' option space. This definition should match the option format described in the relevant RFC but the configuration mechanism will allow any option format as it presently has no means to validate it. Table 7.1. List of standard DHCPv4 options +-------------------------------------------------------------------------+ | | | | |Returned if | | Name | Code | Type | Array? | not | | | | | | requested? | |-----------------------------+------+--------------+--------+------------| |time-offset | 2 | int32 | false | false | |-----------------------------+------+--------------+--------+------------| |routers | 3 | ipv4-address | true | true | |-----------------------------+------+--------------+--------+------------| |time-servers | 4 | ipv4-address | true | false | |-----------------------------+------+--------------+--------+------------| |name-servers | 5 | ipv4-address | true | false | |-----------------------------+------+--------------+--------+------------| |domain-name-servers | 6 | ipv4-address | true | true | |-----------------------------+------+--------------+--------+------------| |log-servers | 7 | ipv4-address | true | false | |-----------------------------+------+--------------+--------+------------| |cookie-servers | 8 | ipv4-address | true | false | |-----------------------------+------+--------------+--------+------------| |lpr-servers | 9 | ipv4-address | true | false | |-----------------------------+------+--------------+--------+------------| |impress-servers | 10 | ipv4-address | true | false | |-----------------------------+------+--------------+--------+------------| |resource-location-servers | 11 | ipv4-address | true | false | |-----------------------------+------+--------------+--------+------------| |boot-size | 13 | uint16 | false | false | |-----------------------------+------+--------------+--------+------------| |merit-dump | 14 | string | false | false | |-----------------------------+------+--------------+--------+------------| |domain-name | 15 | fqdn | false | true | |-----------------------------+------+--------------+--------+------------| |swap-server | 16 | ipv4-address | false | false | |-----------------------------+------+--------------+--------+------------| |root-path | 17 | string | false | false | |-----------------------------+------+--------------+--------+------------| |extensions-path | 18 | string | false | false | |-----------------------------+------+--------------+--------+------------| |ip-forwarding | 19 | boolean | false | false | |-----------------------------+------+--------------+--------+------------| |non-local-source-routing | 20 | boolean | false | false | |-----------------------------+------+--------------+--------+------------| |policy-filter | 21 | ipv4-address | true | false | |-----------------------------+------+--------------+--------+------------| |max-dgram-reassembly | 22 | uint16 | false | false | |-----------------------------+------+--------------+--------+------------| |default-ip-ttl | 23 | uint8 | false | false | |-----------------------------+------+--------------+--------+------------| |path-mtu-aging-timeout | 24 | uint32 | false | false | |-----------------------------+------+--------------+--------+------------| |path-mtu-plateau-table | 25 | uint16 | true | false | |-----------------------------+------+--------------+--------+------------| |interface-mtu | 26 | uint16 | false | false | |-----------------------------+------+--------------+--------+------------| |all-subnets-local | 27 | boolean | false | false | |-----------------------------+------+--------------+--------+------------| |broadcast-address | 28 | ipv4-address | false | false | |-----------------------------+------+--------------+--------+------------| |perform-mask-discovery | 29 | boolean | false | false | |-----------------------------+------+--------------+--------+------------| |mask-supplier | 30 | boolean | false | false | |-----------------------------+------+--------------+--------+------------| |router-discovery | 31 | boolean | false | false | |-----------------------------+------+--------------+--------+------------| |router-solicitation-address | 32 | ipv4-address | false | false | |-----------------------------+------+--------------+--------+------------| |static-routes | 33 | ipv4-address | true | false | |-----------------------------+------+--------------+--------+------------| |trailer-encapsulation | 34 | boolean | false | false | |-----------------------------+------+--------------+--------+------------| |arp-cache-timeout | 35 | uint32 | false | false | |-----------------------------+------+--------------+--------+------------| |ieee802-3-encapsulation | 36 | boolean | false | false | |-----------------------------+------+--------------+--------+------------| |default-tcp-ttl | 37 | uint8 | false | false | |-----------------------------+------+--------------+--------+------------| |tcp-keepalive-interval | 38 | uint32 | false | false | |-----------------------------+------+--------------+--------+------------| |tcp-keepalive-garbage | 39 | boolean | false | false | +-------------------------------------------------------------------------+ Table 7.2. List of standard DHCPv4 options (continued) +------------------------------------------------------------------------------------+ | | | | |Returned if | | Name | Code | Type | Array? | not | | | | | | requested? | |----------------------------------------+------+--------------+--------+------------| |nis-domain | 40 | string | false | false | |----------------------------------------+------+--------------+--------+------------| |nis-servers | 41 | ipv4-address | true | false | |----------------------------------------+------+--------------+--------+------------| |ntp-servers | 42 | ipv4-address | true | false | |----------------------------------------+------+--------------+--------+------------| |vendor-encapsulated-options | 43 | empty | false | false | |----------------------------------------+------+--------------+--------+------------| |netbios-name-servers | 44 | ipv4-address | true | false | |----------------------------------------+------+--------------+--------+------------| |netbios-dd-server | 45 | ipv4-address | true | false | |----------------------------------------+------+--------------+--------+------------| |netbios-node-type | 46 | uint8 | false | false | |----------------------------------------+------+--------------+--------+------------| |netbios-scope | 47 | string | false | false | |----------------------------------------+------+--------------+--------+------------| |font-servers | 48 | ipv4-address | true | false | |----------------------------------------+------+--------------+--------+------------| |x-display-manager | 49 | ipv4-address | true | false | |----------------------------------------+------+--------------+--------+------------| |dhcp-option-overload | 52 | uint8 | false | false | |----------------------------------------+------+--------------+--------+------------| |dhcp-message | 56 | string | false | false | |----------------------------------------+------+--------------+--------+------------| |dhcp-max-message-size | 57 | uint16 | false | false | |----------------------------------------+------+--------------+--------+------------| |vendor-class-identifier | 60 | binary | false | false | |----------------------------------------+------+--------------+--------+------------| |nwip-domain-name | 62 | string | false | false | |----------------------------------------+------+--------------+--------+------------| |nwip-suboptions | 63 | binary | false | false | |----------------------------------------+------+--------------+--------+------------| |nisplus-domain-name | 64 | string | false | false | |----------------------------------------+------+--------------+--------+------------| |nisplus-servers | 65 | ipv4-address | true | false | |----------------------------------------+------+--------------+--------+------------| |tftp-server-name | 66 | string | false | false | |----------------------------------------+------+--------------+--------+------------| |boot-file-name | 67 | string | false | false | |----------------------------------------+------+--------------+--------+------------| |mobile-ip-home-agent | 68 | ipv4-address | true | false | |----------------------------------------+------+--------------+--------+------------| |smtp-server | 69 | ipv4-address | true | false | |----------------------------------------+------+--------------+--------+------------| |pop-server | 70 | ipv4-address | true | false | |----------------------------------------+------+--------------+--------+------------| |nntp-server | 71 | ipv4-address | true | false | |----------------------------------------+------+--------------+--------+------------| |www-server | 72 | ipv4-address | true | false | |----------------------------------------+------+--------------+--------+------------| |finger-server | 73 | ipv4-address | true | false | |----------------------------------------+------+--------------+--------+------------| |irc-server | 74 | ipv4-address | true | false | |----------------------------------------+------+--------------+--------+------------| |streettalk-server | 75 | ipv4-address | true | false | |----------------------------------------+------+--------------+--------+------------| |streettalk-directory-assistance-server | 76 | ipv4-address | true | false | |----------------------------------------+------+--------------+--------+------------| |user-class | 77 | binary | false | false | |----------------------------------------+------+--------------+--------+------------| |client-system | 93 | uint16 | true | false | |----------------------------------------+------+--------------+--------+------------| |client-ndi | 94 |record (uint8,| false | false | | | |uint8, uint8) | | | |----------------------------------------+------+--------------+--------+------------| |uuid-guid | 97 |record (uint8,| false | false | | | | binary) | | | |----------------------------------------+------+--------------+--------+------------| |subnet-selection | 118 | ipv4-address | false | false | |----------------------------------------+------+--------------+--------+------------| |domain-search | 119 | binary | false | false | |----------------------------------------+------+--------------+--------+------------| |vivco-suboptions | 124 | binary | false | false | |----------------------------------------+------+--------------+--------+------------| |vivso-suboptions | 125 | binary | false | false | +------------------------------------------------------------------------------------+ Table 7.3. List of standard DHCP option types +------------------------------------------------------------------------+ | Name | Meaning | |--------------+---------------------------------------------------------| | binary | An arbitrary string of bytes, specified as a set of | | | hexadecimal digits. | |--------------+---------------------------------------------------------| | boolean | Boolean value with allowed values true or false | |--------------+---------------------------------------------------------| | empty | No value, data is carried in suboptions | |--------------+---------------------------------------------------------| | fqdn | Fully qualified domain name (e.g. www.example.com) | |--------------+---------------------------------------------------------| | ipv4-address | IPv4 address in the usual dotted-decimal notation (e.g. | | | 192.0.2.1) | |--------------+---------------------------------------------------------| | ipv6-address | IPv6 address in the usual colon notation (e.g. | | | 2001:db8::1) | |--------------+---------------------------------------------------------| | record | Structured data that may comprise any types (except | | | "record" and "empty") | |--------------+---------------------------------------------------------| | string | Any text | |--------------+---------------------------------------------------------| | uint8 | 8 bit unsigned integer with allowed values 0 to 255 | |--------------+---------------------------------------------------------| | uint16 | 16 bit unsigned integer with allowed values 0 to 65535 | |--------------+---------------------------------------------------------| | uint32 | 32 bit unsigned integer with allowed values 0 to | | | 4294967295 | +------------------------------------------------------------------------+ 7.2.9. Custom DHCPv4 options Kea supports custom (non-standard) DHCPv4 options. Assume that we want to define a new DHCPv4 option called "foo" which will have a code 222 and will convey a single unsigned 32 bit integer value. We can define such an option by using the following entry in the configuration file: "Dhcp4": { "option-def": [ { "name": "foo", "code": 222, "type": "uint32", "array": false, "record-types": "", "space": "dhcp4", "encapsulate": "" }, ... ], ... } The false value of the array parameter determines that the option does NOT comprise an array of "uint32" values but is, instead, a single value. Two other parameters have been left blank: record-types and encapsulate. The former specifies the comma separated list of option data fields if the option comprises a record of data fields. This should be non-empty if the type is set to "record". Otherwise it must be left blank. The latter parameter specifies the name of the option space being encapsulated by the particular option. If the particular option does not encapsulate any option space it should be left blank. Note that the above set of comments define the format of the new option and do not set its values. The name, code and type parameters are required, all others are optional. The array default value is false. The record-types and encapsulate default values are blank (i.e. ""). The default space is "dhcp4". Once the new option format is defined, its value is set in the same way as for a standard option. For example the following commands set a global value that applies to all subnets. "Dhcp4": { "option-data": [ { "name": "foo", "code": 222, "space": "dhcp4", "csv-format": true, "data": "12345" }, ... ], ... } New options can take more complex forms than simple use of primitives (uint8, string, ipv4-address etc): it is possible to define an option comprising a number of existing primitives. Assume we want to define a new option that will consist of an IPv4 address, followed by an unsigned 16 bit integer, followed by a boolean value, followed by a text string. Such an option could be defined in the following way: "Dhcp4": { "option-def": [ { "name": "bar", "code": 223, "space": "dhcp4", "type": "record", "array": false, "record-types": "ipv4-address, uint16, boolean, string", "encapsulate": "" }, ... ], ... } The type is set to "record" to indicate that the option contains multiple values of different types. These types are given as a comma-separated list in the record-types field and should be ones from those listed in Table 7.3, "List of standard DHCP option types". The values of the option are set as follows: "Dhcp4": { "option-data": [ { "name": "bar", "space": "dhcp4", "code": 223, "csv-format": true, "data": "192.0.2.100, 123, true, Hello World" } ], ... } csv-format is set to true to indicate that the data field comprises a command-separated list of values. The values in the data must correspond to the types set in the record-types field of the option definition. Note In the general case, boolean values are specified as true or false, without quotes. Some specific boolean parameters may accept also "true", "false", 0, 1, "0" and "1". Future versions of Kea will accept all those values for all boolean parameters. 7.2.10. DHCPv4 Vendor Specific Options Currently there are two option spaces defined for the DHCPv4 daemon: "dhcp4" (for the top level DHCPv4 options) and "vendor-encapsulated-options-space", which is empty by default but in which options can be defined. Such options will be carried in the Vendor Specific Information option (code 43). The following examples show how to define an option "foo" in that space that has a code 1, and comprises an IPv4 address, an unsigned 16 bit integer and a string. The "foo" option is conveyed in a Vendor Specific Information option. The first step is to define the format of the option: "Dhcp4": { "option-def": [ { "name": "foo", "code": 1, "space": "vendor-encapsulated-options-space", "type": "record", "array": false, "record-types": "ipv4-address, uint16, string", "encapsulate": "" } ], ... } (Note that the option space is set to "vendor-encapsulated-options-space".) Once the option format is defined, the next step is to define actual values for that option: "Dhcp4": { "option-data": [ { "name": "foo", "space": "vendor-encapsulated-options-space", "code": 1, "csv-format": true, "data": "192.0.2.3, 123, Hello World" } ], ... } We also include the Vendor Specific Information option, the option that conveys our sub-option "foo". This is required, else the option will not be included in messages sent to the client. "Dhcp4": { "option-data": [ { "name": "vendor-encapsulated-options" } ], ... } Alternatively, the option can be specified using its code. "Dhcp4": { "option-data": [ { "code": 43 } ], ... } 7.2.11. Nested DHCPv4 Options (Custom Option Spaces) It is sometimes useful to define a completely new option space. This is the case when user creates new option in the standard option space ("dhcp4") and wants this option to convey sub-options. Since they are in a separate space, sub-option codes will have a separate numbering scheme and may overlap with the codes of standard options. Note that creation of a new option space when defining sub-options for a standard option is not required, because it is created by default if the standard option is meant to convey any sub-options (see Section 7.2.10, "DHCPv4 Vendor Specific Options"). Assume that we want to have a DHCPv4 option called "container" with code 222 that conveys two sub-options with codes 1 and 2. First we need to define the new sub-options: "Dhcp4": { "option-def": [ { "name": "subopt1", "code": 1, "space": "isc", "type": "ipv4-address", "record-types": "", "array": false, "encapsulate": "" }, { "name": "subopt2", "code": 2, "space": "isc", "type": "string", "record-types": "", "array": false, "encapsulate": "" } ], ... } Note that we have defined the options to belong to a new option space (in this case, "isc"). The next step is to define a regular DHCPv4 option with our desired code and specify that it should include options from the new option space: "Dhcp4": { "option-def": [ ..., { "name": "container", "code": 222, "space": "dhcp4", "type": "empty", "array": false, "record-types": "", "encapsulate": "isc" } ], ... } The name of the option space in which the sub-options are defined is set in the encapsulate field. The type field is set to "empty" to indicate that this option does not carry any data other than sub-options. Finally, we can set values for the new options: "Dhcp4": { "option-data": [ { "name": "subopt1", "code": 1, "space": "isc", "data": "192.0.2.3" }, } "name": "subopt2", "code": 2, "space": "isc", "data": "Hello world" }, { "name": "container", "code": 222, "space": "dhcp4" } ], ... } Note that it is possible to create an option which carries some data in addition to the sub-options defined in the encapsulated option space. For example, if the "container" option from the previous example was required to carry an uint16 value as well as the sub-options, the type value would have to be set to "uint16" in the option definition. (Such an option would then have the following data structure: DHCP header, uint16 value, sub-options.) The value specified with the data parameter -- which should be a valid integer enclosed in quotes, e.g. "123" -- would then be assigned to the uint16 field in the "container" option. 7.2.12. Unspecified Parameters for DHCPv4 Option Configuration In many cases it is not required to specify all parameters for an option configuration and the default values may be used. However, it is important to understand the implications of not specifying some of them as it may result in configuration errors. The list below explains the behavior of the server when a particular parameter is not explicitly specified: * name - the server requires an option name or option code to identify an option. If this parameter is unspecified, the option code must be specified. * code - the server requires an option name or option code to identify an option. This parameter may be left unspecified if the name parameter is specified. However, this also requires that the particular option has its definition (it is either a standard option or an administrator created a definition for the option using an 'option-def' structure), as the option definition associates an option with a particular name. It is possible to configure an option for which there is no definition (unspecified option format). Configuration of such options requires the use of option code. * space - if the option space is unspecified it will default to 'dhcp4' which is an option space holding DHCPv4 standard options. * data - if the option data is unspecified it defaults to an empty value. The empty value is mostly used for the options which have no payload (boolean options), but it is legal to specify empty values for some options which carry variable length data and which the specification allows for the length of 0. For such options, the data parameter may be omitted in the configuration. * csv-format - if this value is not specified and the definition for the particular option exists, the server will assume that the option data is specified as a list of comma separated values to be assigned to individual fields of the DHCP option. If the definition does not exist for this option, the server will assume that the data parameter contains the option payload in the binary format (represented as a string of hexadecimal digits). Note that not specifying this parameter doesn't imply that it defaults to a fixed value, but the configuration data interpretation also depends on the presence of the option definition. An administrator must be aware if the definition for the particular option exists when this parameter is not specified. It is generally recommended to not specify this parameter only for the options for which the definition exists, e.g. standard options. Setting csv-format to an explicit value will cause the server to strictly check the format of the option data specified. 7.2.13. Stateless Configuration of DHCPv4 Clients The DHCPv4 server supports the stateless client configuration whereby the client has an IP address configured (e.g. using manual configuration) and only contacts the server to obtain other configuration parameters, e.g. addresses of DNS servers. In order to obtain the stateless configuration parameters the client sends the DHCPINFORM message to the server with the "ciaddr" set to the address that the client is currently using. The server unicasts the DHCPACK message to the client that includes the stateless configuration ("yiaddr" not set). The server will respond to the DHCPINFORM when the client is associated with a subnet defined in the server's configuration. An example subnet configuration will look like this: "Dhcp4": { "subnet4": [ { "subnet": "192.0.2.0/24" "option-data": [ { "name": "domain-name-servers", "code": 6, "data": "192.0.2.200,192.0.2.201", "csv-format": true, "space": "dhcp4" } ] } ] } This subnet specifies the single option which will be included in the DHCPACK message to the client in response to DHCPINFORM. Note that the subnet definition does not require the address pool configuration if it will be used solely for the stateless configuration. This server will associate the subnet with the client if one of the following conditions is met: * The DHCPINFORM is relayed and the giaddr matches the configured subnet. * The DHCPINFORM is unicast from the client and the ciaddr matches the configured subnet. * The DHCPINFORM is unicast from the client, the ciaddr is not set but the source address of the IP packet matches the configured subnet. * The DHCPINFORM is not relayed and the IP address on the interface on which the message is received matches the configured subnet. 7.2.14. Client Classification in DHCPv4 The DHCPv4 server includes support for client classification. For a deeper discussion of the classification process see Chapter 12, Client Classification. In certain cases it is useful to differentiate between different types of clients and treat them accordingly. It is envisaged that client classification will be used for changing the behavior of almost any part of the DHCP message processing, including the assignment of leases from different pools, the assignment of different options (or different values of the same options) etc. In the current release of the software however, there are only three mechanisms that take advantage of client classification: subnet selection, assignment of different options, and, for cable modems, there are specific options for use with the TFTP server address and the boot file field. Kea can be instructed to limit access to given subnets based on class information. This is particularly useful for cases where two types of devices share the same link and are expected to be served from two different subnets. The primary use case for such a scenario is cable networks. Here, there are two classes of devices: the cable modem itself, which should be handed a lease from subnet A and all other devices behind the modem that should get a lease from subnet B. That segregation is essential to prevent overly curious users from playing with their cable modems. For details on how to set up class restrictions on subnets, see Section 12.6, "Configuring Subnets With Class Information". The process of doing classification is conducted in three steps. The first step is to assess an incoming packet and assign it to zero or more classes. The second step is to choose a subnet, possibly based on the class information. The third step is to assign options, again possibly based on the class information. There are two methods of doing classification. The first is automatic and relies on examining the values in the vendor class options. Information from these options is extracted and a class name is constructed from it and added to the class list for the packet. The second allows you to specify an expression that is evaluated for each packet. If the result is true the packet is a member of the class. Note Care should be taken with client classification as it is easy for clients that do not meet class criteria to be denied any service altogether. 7.2.14.1. Setting Fixed Fields in Classification It is possible to specify that clients belonging to a particular class should receive packets with specific values in certain fixed fields. In particular, three fixed fields are supported: next-server (that conveys an IPv4 address, which is set in the siaddr field), server-hostname (that conveys a server hostname, can be up to 64 bytes long and will be sent in the sname field) and boot-file-name (that conveys the configuration file, can be up to 128 bytes long and will be sent using file field). Obviously, there are many ways to assign clients to specific classes, but for the PXE clients the client architecture type option (code 93) seems to be particularly suited to make the distinction. The following example checks if the client identifies itself as PXE device with architecture EFI x86-64, and sets several fields if it does. See Section 2.1 of RFC 4578) or the documentation of your client for specific values. "Dhcp4": { "client-classes": [ { "name": "ipxe_efi_x64", "test": "option[93].hex == 0x0009", "next-server": "192.0.2.254", "server-hostname": "hal9000", "boot-file-name": "/dev/null" }, ... ], ... } If there are multiple classes defined and an incoming packet is matched to multiple classes, the class whose name is alphabetically the first is used. 7.2.14.2. Using Vendor Class Information in Classification The server checks whether an incoming packet includes the vendor class identifier option (60). If it does, the content of that option is prepended with "VENDOR_CLASS_", it is interpreted as a class. For example, modern cable modems will send this option with value "docsis3.0" and as a result the packet will belong to class "VENDOR_CLASS_docsis3.0". Note Kea 1.0 and earlier versions performed special actions for clients that were in VENDOR_CLASS_docsis3.0. This is no longer the case in Kea 1.1 and later. In these versions the old behavior can be achieved by defining VENDOR_CLASS_docsis3.0 and setting its next-server and boot-file-name values appropriately. This example shows a configuration using an automatically generated "VENDOR_CLASS_" class. The administrator of the network has decided that addresses from range 192.0.2.10 to 192.0.2.20 are going to be managed by the Dhcp4 server and only clients belonging to the docsis3.0 client class are allowed to use that pool. "Dhcp4": { "subnet4": [ { "subnet": "192.0.2.0/24", "pools": [ { "pool": "192.0.2.10 - 192.0.2.20" } ], "client-class": "VENDOR_CLASS_docsis3.0" } ], ... } 7.2.14.3. Defining and Using Custom Classes The following example shows how to configure a class using an expression and a subnet that makes use of the class. This configuration defines the class named "Client_foo". It is comprised of all clients who's client ids (option 61) start with the string "foo". Members of this class will be given addresses from 192.0.2.10 to 192.0.2.20 and the addresses of their DNS servers set to 192.0.2.1 and 192.0.2.2. "Dhcp4": { "client-classes": [ { "name": "Client_foo", "test": "substring(option[61].hex,0,3) == 'foo'", "option-data": [ { "name": "domain-name-servers", "code": 6, "space": "dhcp4", "csv-format": true, "data": "192.0.2.1, 192.0.2.2" } ] }, ... ], "subnet4": [ { "subnet": "192.0.2.0/24", "pools": [ { "pool": "192.0.2.10 - 192.0.2.20" } ], "client-class": "Client_foo" }, ... ], ... } 7.2.15. DDNS for DHCPv4 As mentioned earlier, kea-dhcp4 can be configured to generate requests to the DHCP-DDNS server (referred to here as "D2" ) to update DNS entries. These requests are known as NameChangeRequests or NCRs. Each NCR contains the following information: 1. Whether it is a request to add (update) or remove DNS entries 2. Whether the change requests forward DNS updates (A records), reverse DNS updates (PTR records), or both. 3. The FQDN, lease address, and DHCID The parameters for controlling the generation of NCRs for submission to D2 are contained in the dhcp-ddns section of the kea-dhcp4 server configuration. The mandatory parameters for the DHCP DDNS configuration are enable-updates which is unconditionally required, and qualifying-suffix which has no default value and is required when enable-updates is set to true. The two (disabled and enabled) minimal DHCP DDNS configurations are: "Dhcp4": { "dhcp-ddns": { "enable-updates": false }, ... } and for example: "Dhcp4": { "dhcp-ddns": { "enable-updates": true, "qualifying-suffix": "example." }, ... } The default values for the "dhcp-ddns" section are as follows: * "server-ip": "127.0.0.1" * "server-port": 53001 * "sender-ip": "" * "sender-port": 0 * "max-queue-size": 1024 * "ncr-protocol": "UDP" * "ncr-format": "JSON" * "override-no-update": false * "override-client-update": false * "replace-client-name": "never" * "generated-prefix": "myhost" 7.2.15.1. DHCP-DDNS Server Connectivity In order for NCRs to reach the D2 server, kea-dhcp4 must be able to communicate with it. kea-dhcp4 uses the following configuration parameters to control this communication: * enable-updates - determines whether or not kea-dhcp4 will generate NCRs. By default, this value is false hence DDNS updates are disabled. To enable DDNS updates set this value to true: * server-ip - IP address on which D2 listens for requests. The default is the local loopback interface at address 127.0.0.1. You may specify either an IPv4 or IPv6 address. * server-port - port on which D2 listens for requests. The default value is 53001. * sender-ip - IP address which kea-dhcp4 should use to send requests to D2. The default value is blank which instructs kea-dhcp4 to select a suitable address. * sender-port - port which kea-dhcp4 should use to send requests to D2. The default value of 0 instructs kea-dhcp4 to select a suitable port. * max-queue-size - maximum number of requests allowed to queue waiting to be sent to D2. This value guards against requests accumulating uncontrollably if they are being generated faster than they can be delivered. If the number of requests queued for transmission reaches this value, DDNS updating will be turned off until the queue backlog has been sufficiently reduced. The intention is to allow the kea-dhcp4 server to continue lease operations without running the risk that its memory usage grows without limit. The default value is 1024. * ncr-protocol - socket protocol use when sending requests to D2. Currently only UDP is supported. TCP may be available in an upcoming release. * ncr-format - packet format to use when sending requests to D2. Currently only JSON format is supported. Other formats may be available in future releases. By default, kea-dhcp-ddns is assumed to be running on the same machine as kea-dhcp4, and all of the default values mentioned above should be sufficient. If, however, D2 has been configured to listen on a different address or port, these values must be altered accordingly. For example, if D2 has been configured to listen on 192.168.1.10 port 900, the following configuration would be required: "Dhcp4": { "dhcp-ddns": { "server-ip": "192.168.1.10", "server-port": 900, ... }, ... } 7.2.15.2. When Does the kea-dhcp4 Server Generate DDNS Requests? kea-dhcp4 follows the behavior prescribed for DHCP servers in RFC 4702. It is important to keep in mind that kea-dhcp4 provides the initial decision making of when and what to update and forwards that information to D2 in the form of NCRs. Carrying out the actual DNS updates and dealing with such things as conflict resolution are within the purview of D2 itself (Chapter 10, The DHCP-DDNS Server). This section describes when kea-dhcp4 will generate NCRs and the configuration parameters that can be used to influence this decision. It assumes that the enable-updates parameter is true. In general, kea-dhcp4 will generate DDNS update requests when: 1. A new lease is granted in response to a DHCP REQUEST 2. An existing lease is renewed but the FQDN associated with it has changed. 3. An existing lease is released in response to a DHCP RELEASE In the second case, lease renewal, two DDNS requests will be issued: one request to remove entries for the previous FQDN and a second request to add entries for the new FQDN. In the last case, a lease release, a single DDNS request to remove its entries will be made. The decision making involved when granting a new lease (the first case) is more involved. When a new lease is granted, kea-dhcp4 will generate a DDNS update request if the DHCP REQUEST contains either the FQDN option (code 81) or the Host Name option (code 12). If both are present, the server will use the FQDN option. By default kea-dhcp4 will respect the FQDN N and S flags specified by the client as shown in the following table: Table 7.4. Default FQDN Flag Behavior +------------------------------------------------------------------------+ | Client | Client Intent | Server Response | Server | | Flags:N-S | | | Flags:N-S-O | |-----------+-------------------------+--------------------+-------------| | | Client wants to do | Server generates | | | 0-0 | forward updates, server | reverse-only | 1-0-0 | | | should do reverse | request | | | | updates | | | |-----------+-------------------------+--------------------+-------------| | | Server should do both | Server generates | | | 0-1 | forward and reverse | request to update | 0-1-0 | | | updates | both directions | | |-----------+-------------------------+--------------------+-------------| | 1-0 | Client wants no updates | Server does not | 1-0-0 | | | done | generate a request | | +------------------------------------------------------------------------+ The first row in the table above represents "client delegation". Here the DHCP client states that it intends to do the forward DNS updates and the server should do the reverse updates. By default, kea-dhcp4 will honor the client's wishes and generate a DDNS request to the D2 server to update only reverse DNS data. The parameter override-client-update can be used to instruct the server to override client delegation requests. When this parameter is true, kea-dhcp4 will disregard requests for client delegation and generate a DDNS request to update both forward and reverse DNS data. In this case, the N-S-O flags in the server's response to the client will be 0-1-1 respectively. (Note that the flag combination N=1, S=1 is prohibited according to RFC 4702. If such a combination is received from the client, the packet will be dropped by kea-dhcp4.) To override client delegation, set the following values in the configuration file: "Dhcp4": { "dhcp-ddns": { "override-client-update": true, ... }, ... } The third row in the table above describes the case in which the client requests that no DNS updates be done. The parameter, override-no-update, can be used to instruct the server to disregard the client's wishes. When this parameter is true, kea-dhcp4 will generate DDNS update requests to kea-dhcp-ddns even if the client requests that no updates be done. The N-S-O flags in the server's response to the client will be 0-1-1. To override client delegation, the following values should be set in your configuration: "Dhcp4": { "dhcp-ddns": { "override-no-update": true, ... }, ... } kea-dhcp4 will always generate DDNS update requests if the client request only contains the Host Name option. In addition it will include an FQDN option in the response to the client with the FQDN N-S-O flags set to 0-1-0 respectively. The domain name portion of the FQDN option will be the name submitted to D2 in the DDNS update request. 7.2.15.3. kea-dhcp4 name generation for DDNS update requests Each NameChangeRequest must of course include the fully qualified domain name whose DNS entries are to be affected. kea-dhcp4 can be configured to supply a portion or all of that name based upon what it receives from the client in the DHCP REQUEST. The default rules for constructing the FQDN that will be used for DNS entries are: 1. If the DHCPREQUEST contains the client FQDN option, the candidate name is taken from there, otherwise it is taken from the Host Name option. 2. If the candidate name is a partial (i.e. unqualified) name then add a configurable suffix to the name and use the result as the FQDN. 3. If the candidate name provided is empty, generate a FQDN using a configurable prefix and suffix. 4. If the client provided neither option, then no DNS action will be taken. These rules can amended by setting the replace-client-name parameter which provides the following modes of behavior: * never - Use the name the client sent. If the client sent no name, do not generate one. This is the default mode. * always - Replace the name the client sent. If the client sent no name, generate one for the client. * when-present - Replace the name the client sent. If the client sent no name, do not generate one. * when-not-present - Use the name the client sent. If the client sent no name, generate one for the client. Note Note that formerly, this parameter was a boolean and permitted only values of true and false. Boolean values will still be accepted but may eventually be deprecated. A value of true equates to when-present, false equates to never. For example, To instruct kea-dhcp4 to always generate the FQDN for a client, set the parameter replace-client-name to always as follows: "Dhcp4": { "dhcp-ddns": { "replace-client-name": "always", ... }, ... } The prefix used in the generation of a FQDN is specified by the generated-prefix parameter. The default value is "myhost". To alter its value, simply set it to the desired string: "Dhcp4": { "dhcp-ddns": { "generated-prefix": "another.host", ... }, ... } The suffix used when generating a FQDN or when qualifying a partial name is specified by the qualifying-suffix parameter. This parameter has no default value, thus it is mandatory when DDNS updates are enabled. To set its value simply set it to the desired string: "Dhcp4": { "dhcp-ddns": { "qualifying-suffix": "foo.example.org", ... }, ... } When generating a name, kea-dhcp4 will construct name of the format: [generated-prefix]-[address-text].[qualifying-suffix]. where address-text is simply the lease IP address converted to a hyphenated string. For example, if the lease address is 172.16.1.10, the qualifying suffix "example.com", and the default value is used for generated-prefix, the generated FQDN would be: myhost-172-16-1-10.example.com. 7.2.16. Next Server (siaddr) In some cases, clients want to obtain configuration from a TFTP server. Although there is a dedicated option for it, some devices may use the siaddr field in the DHCPv4 packet for that purpose. That specific field can be configured using next-server directive. It is possible to define it in the global scope or for a given subnet only. If both are defined, the subnet value takes precedence. The value in subnet can be set to 0.0.0.0, which means that next-server should not be sent. It may also be set to an empty string, which means the same as if it was not defined at all, i.e. use the global value. "Dhcp4": { "next-server": "192.0.2.123", ..., "subnet4": [ { "next-server": "192.0.2.234", ... } ] } 7.2.17. Echoing Client-ID (RFC 6842) The original DHCPv4 specification (RFC 2131) states that the DHCPv4 server must not send back client-id options when responding to clients. However, in some cases that confused clients that did not have MAC address or client-id; see RFC 6842. for details. That behavior has changed with the publication of RFC 6842 which updated RFC 2131. That update states that the server must send client-id if the client sent it. That is Kea's default behavior. However, in some cases older devices that do not support RFC 6842. may refuse to accept responses that include the client-id option. To enable backward compatibility, an optional configuration parameter has been introduced. To configure it, use the following configuration statement: "Dhcp4": { "echo-client-id": false, ... } 7.2.18. Using Client Identifier and Hardware Address The DHCP server must be able to identify the client (and distinguish it from other clients) from which it receives the message. There are many reasons why this identification is required and the most important ones are: * When the client contacts the server to allocate a new lease, the server must store the client identification information in the lease database as a search key. * When the client is trying to renew or release the existing lease, the server must be able to find the existing lease entry in the database for this client, using the client identification information as a search key. * Some configurations use static reservations for the IP addresses and other configuration information. The server's administrator uses client identification information to create these static assignments. * In the dual stack networks there is often a need to correlate the lease information stored in DHCPv4 and DHCPv6 server for a particular host. Using common identification information by the DHCPv4 and DHCPv6 client allows the network administrator to achieve this correlation and better administer the network. DHCPv4 makes use of two distinct identifiers which are placed by the client in the queries sent to the server and copied by the server to its responses to the client: "chaddr" and "client identifier". The former was introduced as a part of the BOOTP specification and it is also used by DHCP to carry the hardware address of the interface used to send the query to the server (MAC address for the Ethernet). The latter is carried in the Client-identifier option, introduced in RFC 2132. RFC 2131 indicates that the server may use both of these identifiers to identify the client but the "client identifier", if present, takes precedence over "chaddr". One of the reasons for this is that "client identifier" is independent from the hardware used by the client to communicate with the server. For example, if the client obtained the lease using one network card and then the network card is moved to another host, the server will wrongly identify this host is the one which has obtained the lease. Moreover, RFC 4361 gives the recommendation to use a DUID (see RFC 3315, the DHCPv6 specification) carried as "client identifier" when dual stack networks are in use to provide consistent identification information of the client, regardless of the protocol type it is using. Kea adheres to these specifications and the "client identifier" by default takes precedence over the value carried in "chaddr" field when the server searches, creates, updates or removes the client's lease. When the server receives a DHCPDISCOVER or DHCPREQUEST message from the client, it will try to find out if the client already has a lease in the database and will hand out that lease rather than allocate a new one. Each lease in the lease database is associated with the "client identifier" and/or "chaddr". The server will first use the "client identifier" (if present) to search the lease. If the lease is found, the server will treat this lease as belonging to the client even if the current "chaddr" and the "chaddr" associated with the lease do not match. This facilitates the scenario when the network card on the client system has been replaced and thus the new MAC address appears in the messages sent by the DHCP client. If the server fails to find the lease using the "client identifier" it will perform another lookup using the "chaddr". If this lookup returns no result, the client is considered as not having a lease and the new lease will be created. A common problem reported by network operators is that poor client implementations do not use stable client identifiers, instead generating a new "client identifier" each time the client connects to the network. Another well known case is when the client changes its "client identifier" during the multi-stage boot process (PXE). In such cases, the MAC address of the client's interface remains stable and using "chaddr" field to identify the client guarantees that the particular system is considered to be the same client, even though its "client identifier" changes. To address this problem, Kea includes a configuration option which enables client identification using "chaddr" only by instructing the server to disregard server to "ignore" the "client identifier" during lease lookups and allocations for a particular subnet. Consider the following simplified server configuration: "Dhcp4": { ... "match-client-id": true, ... "subnet4": [ { "subnet": "192.0.10.0/24", "pools": [ { "pool": "192.0.2.23-192.0.2.87" } ], "match-client-id": false }, { "subnet": "10.0.0.0/8", "pools": [ { "pool": "10.0.0.23-10.0.2.99" } ], } ] } The match-client-id is a boolean value which controls this behavior. The default value of true indicates that the server will use the "client identifier" for lease lookups and "chaddr" if the first lookup returns no results. The false means that the server will only use the "chaddr" to search for client"s lease. Whether the DHCID for DNS updates is generated from the "client identifier" or "chaddr" is controlled through the same parameter accordingly. The match-client-id parameter may appear both in the global configuration scope and/or under any subnet declaration. In the example shown above, the effective value of the match-client-id will be false for the subnet 192.0.10.0/24, because the subnet specific setting of the parameter overrides the global value of the parameter. The effective value of the match-client-id for the subnet 10.0.0.0/8 will be set to true because the subnet declaration lacks this parameter and the global setting is by default used for this subnet. In fact, the global entry for this parameter could be omitted in this case, because true is the default value. It is important to explain what happens when the client obtains its lease for one setting of the match-client-id and then renews when the setting has been changed. First consider the case when the client obtains the lease when the match-client-id is set to true. The server will store the lease information including "client identifier" (if supplied) and "chaddr" in the lease database. When the setting is changed and the client renews the lease the server will determine that it should use the "chaddr" to search for the existing lease. If the client hasn't changed its MAC address the server should successfully find the existing lease. The "client identifier" associated with the returned lease is ignored and the client is allowed to use this lease. When the lease is renewed only the "chaddr" is recorded for this lease according to the new server setting. In the second case the client has the lease with only a "chaddr" value recorded. When the setting is changed to match-client-id set to true the server will first try to use the "client identifier" to find the existing client's lease. This will return no results because the "client identifier" was not recorded for this lease. The server will then use the "chaddr" and the lease will be found. If the lease appears to have no "client identifier" recorded, the server will assume that this lease belongs to the client and that it was created with the previous setting of the match-client-id. However, if the lease contains "client identifier" which is different from the "client identifier" used by the client the lease will be assumed to belong to another client and the new lease will be allocated. 7.2.19. DHCPv4-over-DHCPv6: DHCPv4 Side The support of DHCPv4-over-DHCPv6 transport is described in RFC 7341 and is implemented using cooperating DHCPv4 and DHCPv6 servers. This section is about the configuration of the DHCPv4 side (the DHCPv6 side is described in Section 8.2.20, "DHCPv4-over-DHCPv6: DHCPv6 Side"). Note DHCPv4-over-DHCPv6 support is experimental and the details of the inter-process communication can change: both the DHCPv4 and DHCPv6 sides should be running the same version of Kea. The dhcp4o6-port global parameter specifies the first of the two consecutive ports of the UDP sockets used for the communication between the DHCPv6 and DHCPv4 servers (the DHCPv4 server is bound to ::1 on port + 1 and connected to ::1 on port). With DHCPv4-over-DHCPv6 the DHCPv4 server does not have access to several of the identifiers it would normally use to select a subnet. In order to address this issue three new configuration entires have been added. The presence of any of these allows the subnet to be used with DHCPv4-over-DHCPv6. These entries are: * 4o6-subnet: Takes a prefix (i.e., an IPv6 address followed by a slash and a prefix length) which is matched against the source address. * 4o6-interface-id: Takes a relay interface ID option value. * 4o6-interface: Takes an interface name which is matched against the incoming interface name. The following configuration was used during some tests: { # DHCPv4 conf "Dhcp4": { "interfaces-config": { "interfaces": [ "eno33554984" ] }, "lease-database": { "type": "memfile", "name": "leases4" }, "valid-lifetime": 4000, "subnet4": [ { "subnet": "10.10.10.0/24", "4o6-interface": "eno33554984", "4o6-subnet": "2001:db8:1:1::/64", "pools": [ { "pool": "10.10.10.100 - 10.10.10.199" } ] } ], "dhcp4o6-port": 6767 }, "Logging": { "loggers": [ { "name": "kea-dhcp4", "output_options": [ { "output": "/tmp/kea-dhcp4.log" } ], "severity": "DEBUG", "debuglevel": 0 } ] } } 7.3. Host Reservation in DHCPv4 There are many cases where it is useful to provide a configuration on a per host basis. The most obvious one is to reserve a specific, static address for exclusive use by a given client (host) - the returning client will receive the same address from the server every time, and other clients will generally not receive that address. Another example when the host reservations are applicable is when a host has specific requirements, e.g. a printer that needs additional DHCP options. Yet another possible use case is to define unique names for hosts. Note that there may be cases when the new reservation has been made for the client for the address being currently in use by another client. We call this situation a "conflict". The conflicts get resolved automatically over time as described in subsequent sections. Once the conflict is resolved, the client will keep receiving the reserved configuration when it renews. Host reservations are defined as parameters for each subnet. Each host has to be identified by an identifier, for example the hardware/MAC address. There is an optional reservations array in the Subnet4 element. Each element in that array is a structure that holds information about reservations for a single host. In particular, the structure has to have an identifier that uniquely identifies a host. In the DHCPv4 context, the identifier is usually a hardware or MAC address. In most cases an IP address will be specified. It is also possible to specify a hostname, host specific options or fields carried within DHCPv4 message such as siaddr, sname or file. In Kea 1.0.0 it was only possible to create host reservations using client's hardware address. Host reservations by client identifier, DUID and circuit-id have been added in Kea 1.1.0. The following example shows how to reserve addresses for specific hosts: "subnet4": [ { "pools": [ { "pool": "192.0.2.1 - 192.0.2.200" } ], "subnet": "192.0.2.0/24", "interface": "eth0", "reservations": [ { "hw-address": "1a:1b:1c:1d:1e:1f", "ip-address": "192.0.2.202" }, { "duid": "0a:0b:0c:0d:0e:0f", "ip-address": "192.0.2.100", "hostname": "alice-laptop" }, { "circuit-id": "'charter950'", "ip-address": "192.0.2.203" }, { "client-id": "01:11:22:33:44:55:66", "ip-address": "192.0.2.204" } ] } ] The first entry reserves the 192.0.2.202 address for the client that uses a MAC address of 1a:1b:1c:1d:1e:1f. The second entry reserves the address 192.0.2.100 and the hostname of alice-laptop for the client using a DUID 0a:0b:0c:0d:0e:0f. (Note that if you plan to do DNS updates, it is strongly recommended for the hostnames to be unique.) The third example reserves address 192.0.3.203 to a client whose request would be relayed by a relay agent that inserts a circuid-it option with the value 'charter950'. The fourth entry reserves address 192.0.2.204 for a client that uses a client identifier with value 01:11:22:33:44:55:66. The above example is used for ilustrational purposes only and in actual deployments it is recommended to use as few types as possible (preferably just one). See Section 7.3.9, "Fine Tuning DHCPv4 Host Reservation" for a detailed discussion of this point. Making a reservation for a mobile host that may visit multiple subnets requires a separate host definition in each subnet it is expected to visit. It is not allowed to define multiple host definitions with the same hardware address in a single subnet. Multiple host definitions with the same hardware address are valid if each is in a different subnet. Adding host reservation incurs a performance penalty. In principle, when a server that does not support host reservation responds to a query, it needs to check whether there is a lease for a given address being considered for allocation or renewal. The server that also supports host reservation has to perform additional checks: not only if the address is currently used (i.e. if there is a lease for it), but also whether the address could be used by someone else (i.e. there is a reservation for it). That additional check incurs additional overhead. 7.3.1. Address Reservation Types In a typical scenario there is an IPv4 subnet defined, e.g. 192.0.2.0/24, with certain part of it dedicated for dynamic allocation by the DHCPv4 server. That dynamic part is referred to as a dynamic pool or simply a pool. In principle, a host reservation can reserve any address that belongs to the subnet. The reservations that specify addresses that belong to configured pools are called "in-pool reservations". In contrast, those that do not belong to dynamic pools are called "out-of-pool reservations". There is no formal difference in the reservation syntax and both reservation types are handled uniformly. However, upcoming releases may offer improved performance if there are only out-of-pool reservations as the server will be able to skip reservation checks when dealing with existing leases. Therefore, system administrators are encouraged to use out-of-pool reservations if possible. 7.3.2. Conflicts in DHCPv4 Reservations As the reservations and lease information are stored separately, conflicts may arise. Consider the following series of events. The server has configured the dynamic pool of addresses from the range of 192.0.2.10 to 192.0.2.20. Host A requests an address and gets 192.0.2.10. Now the system administrator decides to reserve address 192.0.2.10 for Host B. In general, reserving an address that is currently assigned to someone else is not recommended, but there are valid use cases where such an operation is warranted. The server now has a conflict to resolve. Let's analyze the situation here. If Host B boots up and requests an address, the server is not able to assign the reserved address 192.0.2.10. A naive approach would to be immediately remove the existing lease for the Host A and create a new one for the Host B. That would not solve the problem, though, because as soon as the Host B gets the address, it will detect that the address is already in use by the Host A and would send the DHCPDECLINE message. Therefore, in this situation, the server has to temporarily assign a different address (not matching what has been reserved) to the Host B. When Host A renews its address, the server will discover that the address being renewed is now reserved for another host - Host B. Therefore the server will inform the Host A that it is no longer allowed to use it by sending a DHCPNAK message. The server will not remove the lease, though, as there's small chance that the DHCPNAK may be lost if the network is lossy. If that happens, the client will not receive any responses, so it will retransmit its DHCPREQUEST packet. Once the DHCPNAK is received by Host A, it will revert to the server discovery and will eventually get a different address. Besides allocating a new lease, the server will also remove the old one. As a result, address 192.0.2.10 will become free . When Host B tries to renew its temporarily assigned address, the server will detect that it has a valid lease, but there is a reservation for a different address. The server will send DHCPNAK to inform Host B that its address is no longer usable, but will keep its lease (again, the DHCPNAK may be lost, so the server will keep it, until the client returns for a new address). Host B will revert to the server discovery phase and will eventually send a DHCPREQUEST message. This time the server will find out that there is a reservation for that host and the reserved address 192.0.2.10 is not used, so it will be granted. It will also remove the lease for the temporarily assigned address that Host B previously obtained. This recovery will succeed, even if other hosts will attempt to get the reserved address. Had the Host C requested address 192.0.2.10 after the reservation was made, the server will either offer a different address (when responding to DHCPDISCOVER) or would send DHCPNAK (when responding to DHCPREQUEST). This recovery mechanism allows the server to fully recover from a case where reservations conflict with the existing leases. This procedure takes time and will roughly take as long as the value set for of renew-timer. The best way to avoid such recovery is to not define new reservations that conflict with existing leases. Another recommendation is to use out-of-pool reservations. If the reserved address does not belong to a pool, there is no way that other clients could get this address. 7.3.3. Reserving a Hostname When the reservation for a client includes the hostname, the server will return this hostname to the client in the Client FQDN or Hostname options. The server responds with the Client FQDN option only if the client has included Client FQDN option in its message to the server. The server will respond with the Hostname option if the client included Hostname option in its message to the server or when the client requested Hostname option using Parameter Request List option. The server will return the Hostname option even if it is not configured to perform DNS updates. The reserved hostname always takes precedence over the hostname supplied by the client or the autogenerated (from the IPv4 address) hostname. The server qualifies the reserved hostname with the value of the qualifying-suffix parameter. For example, the following subnet configuration: { "subnet4": [ { "subnet": "10.0.0.0/24", "pools": [ { "pool": "10.0.0.10-10.0.0.100" } ], "reservations": [ { "hw-address": "aa:bb:cc:dd:ee:ff", "hostname": "alice-laptop" } ] }], "dhcp-ddns": { "enable-updates": true, "qualifying-suffix": "example.isc.org." } } will result in assigning the "alice-laptop.example.isc.org." hostname to the client using the MAC address "aa:bb:cc:dd:ee:ff". If the qualifying-suffix is not specified, the default (empty) value will be used, and in this case the value specified as a hostname will be treated as fully qualified name. Thus, by leaving the qualifying-suffix empty it is possible to qualify hostnames for the different clients with different domain names: { "subnet4": [ { "subnet": "10.0.0.0/24", "pools": [ { "pool": "10.0.0.10-10.0.0.100" } ], "reservations": [ { "hw-address": "aa:bb:cc:dd:ee:ff", "hostname": "alice-laptop.isc.org." }, { "hw-address": "12:34:56:78:99:AA", "hostname": "mark-desktop.example.org." } ] }], "dhcp-ddns": { "enable-updates": true, } } 7.3.4. Including Specific DHCPv4 Options in Reservations Kea 1.1.0 introduced the ability to specify options on a per host basis. The options follow the same rules as any other options. These can be standard options (see Section 7.2.8, "Standard DHCPv4 Options"), custom options (see Section 7.2.9, "Custom DHCPv4 options") or vendor specific options (see Section 7.2.10, "DHCPv4 Vendor Specific Options"). The following example demonstrates how standard options can be defined. { "subnet4": [ { "reservations": [ { "hw-address": "aa:bb:cc:dd:ee:ff", "ip-address": "192.0.2.1", "option-data": [ { "name": "cookie-servers", "data": "10.1.1.202,10.1.1.203" }, { "name": "log-servers", "data": "10.1.1.200,10.1.1.201" } ] } ] } ] } Vendor specific options can be reserved in a similar manner: { "subnet4": [ { "reservations": [ { "hw-address": "aa:bb:cc:dd:ee:ff", "ip-address": "10.0.0.7", "option-data": [ { "name": "vivso-suboptions", "data": "4491" }, { "name": "tftp-servers", "space": "vendor-4491", "data": "10.1.1.202,10.1.1.203" } ] } ] } ] } Options defined on host level have the highest priority. In other words, if there are options defined with the same type on global, subnet, class and host level, the host specific values will be used. 7.3.5. Reserving Next Server, Server Hostname and Boot File Name BOOTP/DHCPv4 messages include "siaddr", "sname" and "file" fields. Even though, DHCPv4 includes corresponding options, such as option 66 and option 67, some clients may not support these options. For this reason, server administrators often use the "siaddr", "sname" and "file" fields instead. With Kea, it is possible to make static reservations for these DHCPv4 message fields: { "subnet4": [ { "reservations": [ { "hw-address": "aa:bb:cc:dd:ee:ff", "next-server": "10.1.1.2", "server-hostname": "server-hostname.example.org", "boot-file-name": "/tmp/bootfile.efi" } ] } ] } Note that those parameters can be specified in combination with other parameters for a reservation, e.g. reserved IPv4 address. These parameters are optional, i.e. a subset of them can specified, or all of them can be omitted. 7.3.6. Reserving Client Classes in DHCPv4 Section 12.4, "Using Expressions In Classification" explains how to configure the server to assign classes to a client based on the content of the options that this client sends to the server. Host reservations mechanisms also allow for statically assigning classes to the clients. The definitions of these classes must exist in the Kea configuration. The following configuration snippet shows how to specify that a client belongs to classes reserved-class1 and reserved-class2. Those classes are associated with specific options being sent to the clients which belong to them. { "client-classes": [ { "name": "reserved-class1", "option-data": [ { "name": "routers", "data": "10.0.0.200" } ] }, { "name": "reserved-class2", "option-data": [ { "name": "domain-name-servers", "data": "10.0.0.201" } ] } ], "subnet4": [ { "subnet": "10.0.0.0/24", "pools": [ { "pool": "10.0.0.10-10.0.0.100" } ], "reservations": [ { "hw-address": "aa:bb:cc:dd:ee:ff", "client-classes": [ "reserved-class1", "reserved-class2" ] } ] } ] } Static class assignments, as shown above, can be used in conjuction with classification using expressions. 7.3.7. Storing Host Reservations in MySQL or PostgreSQL It is possible to store host reservations in MySQL or PostgreSQL database. See Section 7.2.3, "Hosts Storage" for information on how to configure Kea to use reservations stored in MySQL or PostgreSQL. Kea does not provide any dedicated tools for managing reservations in a database. The Kea wiki http://kea.isc.org/wiki/HostReservationsHowTo provides detailed information and examples of how reservations can be inserted into the database. Note In Kea 1.1.0 maximum length of an option specified per host is arbitrarily set to 4096 bytes. 7.3.8. Storing host reservations in CQL (Cassandra) Kea currently does not support storing reservations in Cassandra (CQL). 7.3.9. Fine Tuning DHCPv4 Host Reservation The host reservation capability introduces additional restrictions for the allocation engine (the component of Kea that selects an address for a client) during lease selection and renewal. In particular, three major checks are necessary. First, when selecting a new lease, it is not sufficient for a candidate lease to not be used by another DHCP client. It also must not be reserved for another client. Second, when renewing a lease, additional check must be performed whether the address being renewed is not reserved for another client. Finally, when a host renews an address, the server has to check whether there is a reservation for this host, so the existing (dynamically allocated) address should be revoked and the reserved one be used instead. Some of those checks may be unnecessary in certain deployments and not performing them may improve performance. The Kea server provides the reservation-mode configuration parameter to select the types of reservations allowed for the particular subnet. Each reservation type has different constraints for the checks to be performed by the server when allocating or renewing a lease for the client. Allowed values are: * all - enables all host reservation types. This is the default value. This setting is the safest and the most flexible. It allows in-pool and out-of-pool reservations. As all checks are conducted, it is also the slowest. * out-of-pool - allows only out of pool host reservations. With this setting in place, the server may assume that all host reservations are for addresses that do not belong to the dynamic pool. Therefore it can skip the reservation checks when dealing with in-pool addresses, thus improving performance. Do not use this mode if any of your reservations use in-pool address. Caution is advised when using this setting: Kea 1.1.0 does not sanity check the reservations against reservation-mode and misconfiguration may cause problems. * disabled - host reservation support is disabled. As there are no reservations, the server will skip all checks. Any reservations defined will be completely ignored. As the checks are skipped, the server may operate faster in this mode. An example configuration that disables reservation looks like follows: "Dhcp4": { "subnet4": [ { "subnet": "192.0.2.0/24", "reservation-mode": "disabled", ... } ] } Another aspect of the host reservations are the different types of identifiers. Kea 1.1.0 supports four types of identifiers (hw-address, duid, client-id and circuit-id), but more identifier types are likely to be added in the future. This is beneficial from a usability perspective. However, there is a drawback. For each incoming packet Kea has to to extract each identifier type and then query the database to see if there is a reservation done by this particular identifier. If nothing is found, the next identifier is extracted and the next query is issued. This process continues until either a reservation is found or all identifier types have been checked. Over time with an increasing number of supported identifier types, Kea would become slower and slower. To address this problem, a parameter called host-reservation-identifiers has been introduced. It takes a list of identifier types as a parameter. Kea will check only those identifier types enumerated in host-reservation-identifiers. From a performance perspective the number of identifier types should be kept to a minimum, ideally limited to one. If your deployment uses several reservation types, please enumerate them from most to least frequently used as this increases the chances of Kea finding the reservation using the fewest number of queries. An example of host reservation identifiers looks as follows: "host-reservation-identifiers": [ "circuit-id", "hw-address", "duid", "client-id" ], "subnet4": [ { "subnet": "192.0.2.0/24", ... } ] If not specified, the default value is: "host-reservation-identifiers": [ "hw-address", "duid", "circuit-id", "client-id" ] 7.4. Server Identifier in DHCPv4 The DHCPv4 protocol uses a "server identifier" to allow clients to discriminate between several servers present on the same link: this value is an IPv4 address of the server. The server chooses the IPv4 address of the interface on which the message from the client (or relay) has been received. A single server instance will use multiple server identifiers if it is receiving queries on multiple interfaces. Currently there is no mechanism to override the default server identifiers by an administrator. In the future, the configuration mechanism will be used to specify the custom server identifier. 7.5. How the DHCPv4 Server Selects a Subnet for the Client The DHCPv4 server differentiates between the directly connected clients, clients trying to renew leases and clients sending their messages through relays. For directly connected clients, the server will check the configuration for the interface on which the message has been received and, if the server configuration doesn't match any configured subnet, the message is discarded. Assuming that the server's interface is configured with the IPv4 address 192.0.2.3, the server will only process messages received through this interface from a directly connected client if there is a subnet configured to which this IPv4 address belongs, e.g. 192.0.2.0/24. The server will use this subnet to assign IPv4 address for the client. The rule above does not apply when the client unicasts its message, i.e. is trying to renew its lease. Such a message is accepted through any interface. The renewing client sets ciaddr to the currently used IPv4 address. The server uses this address to select the subnet for the client (in particular, to extend the lease using this address). If the message is relayed it is accepted through any interface. The giaddr set by the relay agent is used to select the subnet for the client. It is also possible to specify a relay IPv4 address for a given subnet. It can be used to match incoming packets into a subnet in uncommon configurations, e.g. shared subnets. See Section 7.5.1, "Using a Specific Relay Agent for a Subnet" for details. Note The subnet selection mechanism described in this section is based on the assumption that client classification is not used. The classification mechanism alters the way in which a subnet is selected for the client, depending on the classes to which the client belongs. 7.5.1. Using a Specific Relay Agent for a Subnet A relay has to have an interface connected to the link on which the clients are being configured. Typically the relay has an IPv4 address configured on that interface that belongs to the subnet from which the server will assign addresses. In the typical case, the server is able to use the IPv4 address inserted by the relay (in the giaddr field of the DHCPv4 packet) to select the appropriate subnet. However, that is not always the case. In certain uncommon -- but valid -- deployments, the relay address may not match the subnet. This usually means that there is more than one subnet allocated for a given link. The two most common examples where this is the case are long lasting network renumbering (where both old and new address space is still being used) and a cable network. In a cable network both cable modems and the devices behind them are physically connected to the same link, yet they use distinct addressing. In such a case, the DHCPv4 server needs additional information (the IPv4 address of the relay) to properly select an appropriate subnet. The following example assumes that there is a subnet 192.0.2.0/24 that is accessible via a relay that uses 10.0.0.1 as its IPv4 address. The server will be able to select this subnet for any incoming packets that came from a relay that has an address in 192.0.2.0/24 subnet. It will also select that subnet for a relay with address 10.0.0.1. "Dhcp4": { "subnet4": [ { "subnet": "192.0.2.0/24", "pools": [ { "pool": "192.0.2.10 - 192.0.2.20" } ], "relay": { "ip-address": "10.0.0.1" }, ... } ], ... } 7.5.2. Segregating IPv4 Clients in a Cable Network In certain cases, it is useful to mix relay address information, introduced in Section 7.5.1, "Using a Specific Relay Agent for a Subnet" with client classification, explained in Chapter 12, Client Classification. One specific example is cable network, where typically modems get addresses from a different subnet than all devices connected behind them. Let us assume that there is one CMTS (Cable Modem Termination System) with one CM MAC (a physical link that modems are connected to). We want the modems to get addresses from the 10.1.1.0/24 subnet, while everything connected behind modems should get addresses from another subnet (192.0.2.0/24). The CMTS that acts as a relay uses address 10.1.1.1. The following configuration can serve that configuration: "Dhcp4": { "subnet4": [ { "subnet": "10.1.1.0/24", "pools": [ { "pool": "10.1.1.2 - 10.1.1.20" } ], "client-class" "docsis3.0", "relay": { "ip-address": "10.1.1.1" } }, { "subnet": "192.0.2.0/24", "pools": [ { "pool": "192.0.2.10 - 192.0.2.20" } ], "relay": { "ip-address": "10.1.1.1" } } ], ... } 7.6. Duplicate Addresses (DHCPDECLINE Support) The DHCPv4 server is configured with a certain pool of addresses that it is expected to hand out to the DHCPv4 clients. It is assumed that the server is authoritative and has complete jurisdiction over those addresses. However, due to various reasons, such as misconfiguration or a faulty client implementation that retains its address beyond the valid lifetime, there may be devices connected that use those addresses without the server's approval or knowledge. Such an unwelcome event can be detected by legitimate clients (using ARP or ICMP Echo Request mechanisms) and reported to the DHCPv4 server using a DHCPDECLINE message. The server will do a sanity check (if the client declining an address really was supposed to use it), and then will conduct a clean up operation. Any DNS entries related to that address will be removed, the fact will be logged and hooks will be triggered. After that is done, the address will be marked as declined (which indicates that it is used by an unknown entity and thus not available for assignment to anyone) and a probation time will be set on it. Unless otherwise configured, the probation period lasts 24 hours. After that period, the server will recover the lease (i.e. put it back into the available state) and the address will be available for assignment again. It should be noted that if the underlying issue of a misconfigured device is not resolved, the duplicate address scenario will repeat. On the other hand, it provides an opportunity to recover from such an event automatically, without any sysadmin intervention. To configure the decline probation period to a value other than the default, the following syntax can be used: "Dhcp4": { "decline-probation-period": 3600, "subnet4": [ ... ], ... } The parameter is expressed in seconds, so the example above will instruct the server to recycle declined leases after an hour. There are several statistics and hook points associated with the Decline handling procedure. The lease4_decline hook is triggered after the incoming DHCPDECLINE message has been sanitized and the server is about to decline the lease. The declined-addresses statistic is increased after the hook returns (both global and subnet specific variants). (See Section 7.7, "Statistics in the DHCPv4 Server" and Chapter 13, Hooks Libraries for more details on DHCPv4 statistics and Kea hook points.) Once the probation time elapses, the declined lease is recovered using the standard expired lease reclamation procedure, with several additional steps. In particular, both declined-addresses statistics (global and subnet specific) are decreased. At the same time, reclaimed-declined-addresses statistics (again in two variants, global and subnet specific) are increased. Note about statistics: The server does not decrease the assigned-addresses statistics when a DHCPDECLINE is received and processed successfully. While technically a declined address is no longer assigned, the primary usage of the assigned-addresses statistic is to monitor pool utilization. Most people would forget to include declined-addresses in the calculation, and simply do assigned-addresses/total-addresses. This would have a bias towards under-representing pool utilization. As this has a potential for major issues, we decided not to decrease assigned addresses immediately after receiving DHCPDECLINE, but to do it later when we recover the address back to the available pool. 7.7. Statistics in the DHCPv4 Server Note This section describes DHCPv4-specific statistics. For a general overview and usage of statistics, see Chapter 14, Statistics. The DHCPv4 server supports the following statistics: Table 7.5. DHCPv4 Statistics +-----------------------------------------------------------------------------+ | Statistic |Data Type|Description | |---------------------------------------+---------+---------------------------| | | |Number of DHCPv4 packets | | | |received. This includes all| | pkt4-received | integer |packets: valid, bogus, | | | |corrupted, rejected etc. | | | |This statistic is expected | | | |to grow rapidly. | |---------------------------------------+---------+---------------------------| | | |Number of DHCPDISCOVER | | | |packets received. This | | | |statistic is expected to | | | |grow. Its increase means | | pkt4-discover-received | integer |that clients that just | | | |booted started their | | | |configuration process and | | | |their initial packets | | | |reached your server. | |---------------------------------------+---------+---------------------------| | | |Number of DHCPOFFER packets| | | |received. This statistic is| | | |expected to remain zero at | | | |all times, as DHCPOFFER | | | |packets are sent by the | | | |server and the server is | | | |never expected to receive | | pkt4-offer-received | integer |them. Non-zero value | | | |indicates an error. One | | | |likely cause would be a | | | |misbehaving relay agent | | | |that incorrectly forwards | | | |DHCPOFFER messages towards | | | |the server, rather back to | | | |the clients. | |---------------------------------------+---------+---------------------------| | | |Number of DHCPREQUEST | | | |packets received. This | | | |statistic is expected to | | | |grow. Its increase means | | pkt4-request-received | integer |that clients that just | | | |booted received server's | | | |response (DHCPOFFER), | | | |accepted it and now | | | |requesting an address | | | |(DHCPREQUEST). | |---------------------------------------+---------+---------------------------| | | |Number of DHCPACK packets | | | |received. This statistic is| | | |expected to remain zero at | | | |all times, as DHCPACK | | | |packets are sent by the | | | |server and the server is | | | |never expected to receive | | pkt4-ack-received | integer |them. Non-zero value | | | |indicates an error. One | | | |likely cause would be a | | | |misbehaving relay agent | | | |that incorrectly forwards | | | |DHCPACK messages towards | | | |the server, rather back to | | | |the clients. | |---------------------------------------+---------+---------------------------| | | |Number of DHCPNAK packets | | | |received. This statistic is| | | |expected to remain zero at | | | |all times, as DHCPNAK | | | |packets are sent by the | | | |server and the server is | | | |never expected to receive | | pkt4-nak-received | integer |them. Non-zero value | | | |indicates an error. One | | | |likely cause would be a | | | |misbehaving relay agent | | | |that incorrectly forwards | | | |DHCPNAK messages towards | | | |the server, rather back to | | | |the clients. | |---------------------------------------+---------+---------------------------| | | |Number of DHCPRELEASE | | | |packets received. This | | | |statistic is expected to | | pkt4-release-received | integer |grow. Its increase means | | | |that clients that had an | | | |address are shutting down | | | |or stop using their | | | |addresses. | |---------------------------------------+---------+---------------------------| | | |Number of DHCPDECLINE | | | |packets received. This | | | |statistic is expected to | | | |remain close to zero. Its | | | |increase means that a | | pkt4-decline-received | integer |client that leased an | | | |address, but discovered | | | |that the address is | | | |currently used by an | | | |unknown device in your | | | |network. | |---------------------------------------+---------+---------------------------| | | |Number of DHCPINFORM | | | |packets received. This | | | |statistic is expected to | | | |grow. Its increase means | | pkt4-inform-received | integer |that there are clients that| | | |either do not need an | | | |address or already have an | | | |address and are interested | | | |only in getting additional | | | |configuration parameters. | |---------------------------------------+---------+---------------------------| | | |Number of packets received | | | |of an unknown type. | | | |Non-zero value of this | | | |statistic indicates that | | pkt4-unknown-received | integer |the server received a | | | |packet that it wasn't able | | | |to recognize: either with | | | |unsupported type or | | | |possibly malformed (without| | | |message type option). | |---------------------------------------+---------+---------------------------| | | |Number of DHCPv4 packets | | | |sent. This statistic is | | | |expected to grow every time| | | |the server transmits a | | | |packet. In general, it | | | |should roughly match | | pkt4-sent | integer |pkt4-received, as most | | | |incoming packets cause | | | |server to respond. There | | | |are exceptions (e.g. | | | |DHCPRELEASE), so do not | | | |worry, if it is lesser than| | | |pkt4-received. | |---------------------------------------+---------+---------------------------| | | |Number of DHCPOFFER packets| | | |sent. This statistic is | | | |expected to grow in most | | | |cases after a DHCPDISCOVER | | | |is processed. There are | | pkt4-offer-sent | integer |certain uncommon, but valid| | | |cases where incoming | | | |DHCPDISCOVER is dropped, | | | |but in general this | | | |statistic is expected to be| | | |close to | | | |pkt4-discover-received. | |---------------------------------------+---------+---------------------------| | | |Number of DHCPACK packets | | | |sent. This statistic is | | | |expected to grow in most | | | |cases after a DHCPREQUEST | | | |is processed. There are | | pkt4-ack-sent | integer |certain cases where DHCPNAK| | | |is sent instead. In | | | |general, the sum of | | | |pkt4-ack-sent and | | | |pkt4-nak-sent should be | | | |close to | | | |pkt4-request-received. | |---------------------------------------+---------+---------------------------| | | |Number of DHCPNAK packets | | | |sent. This statistic is | | | |expected to grow when the | | | |server chooses to not honor| | pkt4-nak-sent | integer |the address requested by a | | | |client. In general, the sum| | | |of pkt4-ack-sent and | | | |pkt4-nak-sent should be | | | |close to | | | |pkt4-request-received. | |---------------------------------------+---------+---------------------------| | | |Number of incoming packets | | | |that could not be parsed. A| | | |non-zero value of this | | | |statistic indicates that | | pkt4-parse-failed | integer |the server received | | | |malformed or truncated | | | |packet. This may indicate | | | |problems in your network, | | | |faulty clients or a bug in | | | |the server. | |---------------------------------------+---------+---------------------------| | | |Number of incoming packets | | | |that were dropped. The | | | |exact reason for dropping | | | |packets is logged, but the | | | |most common reasons may be:| | pkt4-receive-drop | integer |an unacceptable packet | | | |type, direct responses are | | | |forbidden, or the server-id| | | |sent by the client does not| | | |match the server's | | | |server-id. | |---------------------------------------+---------+---------------------------| | | |The total number of | | | |addresses available for | | | |DHCPv4 management. In other| | | |words, this is the sum of | | | |all addresses in all | | | |configured pools. This | | | |statistic changes only | | | |during configuration | | | |changes. Note it does not | | subnet[id].total-addresses | integer |take into account any | | | |addresses that may be | | | |reserved due to host | | | |reservation. The id is the | | | |subnet-id of a given | | | |subnet. This statistic is | | | |exposed for each subnet | | | |separately. This statistic | | | |is reset during | | | |reconfiguration event. | |---------------------------------------+---------+---------------------------| | | |This statistic shows the | | | |number of assigned | | | |addresses in a given | | | |subnet. It increases every | | | |time a new lease is | | | |allocated (as a result of | | | |receiving a DHCPREQUEST | | | |message) and is decreased | | subnet[id].assigned-addresses | integer |every time a lease is | | | |released (a DHCPRELEASE | | | |message is received) or | | | |expires. The id is the | | | |subnet-id of the subnet. | | | |This statistic is exposed | | | |for each subnet separately.| | | |This statistic is reset | | | |during reconfiguration | | | |event. | |---------------------------------------+---------+---------------------------| | | |This statistic shows the | | | |number of IPv4 addresses | | | |that are currently | | | |declined, so counting the | | | |number of leases currently | | | |unavailable. Once a lease | | | |is recovered, this | | | |statistic will be | | | |decreased. Ideally, this | | declined-addresses | integer |statistic should be zero. | | | |If this statistic is | | | |non-zero (or worse | | | |increasing), a network | | | |administrator should | | | |investigate if there is a | | | |misbehaving device in his | | | |network. This is a global | | | |statistic that covers all | | | |subnets. | |---------------------------------------+---------+---------------------------| | | |This statistic shows the | | | |number of IPv4 addresses | | | |that are currently declined| | | |in a given subnet, so is a | | | |count of the number of | | | |leases currently | | | |unavailable. Once a lease | | | |is recovered, this | | | |statistic will be | | | |decreased. Ideally, this | | subnet[id].declined-addresses | integer |statistic should be zero. | | | |If this statistic is | | | |non-zero (or worse | | | |increasing), a network | | | |administrator should | | | |investigate if there is a | | | |misbehaving device in his | | | |network. The id is the | | | |subnet-id of a given | | | |subnet. This statistic is | | | |exposed for each subnet | | | |separately. | |---------------------------------------+---------+---------------------------| | | |This statistic shows the | | | |number of IPv4 addresses | | | |that were declined, but | | | |have now been recovered. | | | |Unlike declined-addresses, | | | |this statistic never | | reclaimed-declined-addresses | integer |decreases. It can be used | | | |as a long term indicator of| | | |how many actual valid | | | |Declines were processed and| | | |recovered from. This is a | | | |global statistic that | | | |covers all subnets. | |---------------------------------------+---------+---------------------------| | | |This statistic shows the | | | |number of IPv4 addresses | | | |that were declined, but | | | |have now been recovered. | | | |Unlike declined-addresses, | | | |this statistic never | | | |decreases. It can be used | |subnet[id].reclaimed-declined-addresses| integer |as a long term indicator of| | | |how many actual valid | | | |Declines were processed and| | | |recovered from. The id is | | | |the subnet-id of a given | | | |subnet. This statistic is | | | |exposed for each subnet | | | |separately. | +-----------------------------------------------------------------------------+ 7.8. Management API for the DHCPv4 Server The management API allows the issuing of specific management commands, such as statistics retrieval, reconfiguration or shutdown. For more details, see Chapter 15, Management API. Currently the only supported communication channel type is UNIX stream socket. By default there are no sockets open. To instruct Kea to open a socket, the following entry in the configuration file can be used: "Dhcp4": { "control-socket": { "socket-type": "unix", "socket-name": "/path/to/the/unix/socket" }, "subnet4": [ ... ], ... } The length of the path specified by the socket-name parameter is restricted by the maximum length for the unix socket name on your operating system, i.e. the size of the sun_path field in the sockaddr_un structure, decreased by 1. This value varies on different operating systems between 91 and 107 characters. Typical values are 107 on Linux and 103 on FreeBSD. Communication over control channel is conducted using JSON structures. See the Control Channel section in the Kea Developer's Guide for more details. The DHCPv4 server supports statistic-get, statistic-reset, statistic-remove, statistic-get-all, statistic-reset-all and statistic-remove-all, specified in Section 14.3, "Commands for Manipulating Statistics". It also supports list-commands and shutdown, specified in Section 15.3.2, "list-commands" and Section 15.3.3, "shutdown", respectively. 7.9. Supported DHCP Standards The following standards are currently supported: * Dynamic Host Configuration Protocol, RFC 2131: Supported messages are DHCPDISCOVER (1), DHCPOFFER (2), DHCPREQUEST (3), DHCPRELEASE (7), DHCPINFORM (8), DHCPACK (5), and DHCPNAK(6). * DHCP Options and BOOTP Vendor Extensions, RFC 2132: Supported options are: PAD (0), END(255), Message Type(53), DHCP Server Identifier (54), Domain Name (15), DNS Servers (6), IP Address Lease Time (51), Subnet mask (1), and Routers (3). * DHCP Relay Agent Information Option, RFC 3046: Relay Agent Information option is supported. * Vendor-Identifying Vendor Options for Dynamic Host Configuration Protocol version 4, RFC 3925: Vendor-Identifying Vendor Class and Vendor-Identifying Vendor-Specific Information options are supported. * Client Identifier Option in DHCP Server Replies, RFC 6842: Server by default sends back client-id option. That capability may be disabled. See Section 7.2.17, "Echoing Client-ID (RFC 6842)" for details. 7.10. DHCPv4 Server Limitations These are the current limitations of the DHCPv4 server software. Most of them are reflections of the current stage of development and should be treated as "not implemented yet", rather than actual limitations. However, some of them are implications of the design choices made. Those are clearly marked as such. * BOOTP (RFC 951) is not supported. This is a design choice: BOOTP support is not planned. * On Linux and BSD system families the DHCP messages are sent and received over the raw sockets (using LPF and BPF) and all packet headers (including data link layer, IP and UDP headers) are created and parsed by Kea, rather than the system kernel. Currently, Kea can only parse the data link layer headers with a format adhering to IEEE 802.3 standard and assumes this data link layer header format for all interfaces. Hence, Kea will fail to work on interfaces which use different data link layer header formats (e.g. Infiniband). * The DHCPv4 server does not verify that assigned address is unused. According to RFC 2131, the allocating server should verify that address is not used by sending ICMP echo request. Chapter 8. The DHCPv6 Server Table of Contents 8.1. Starting and Stopping the DHCPv6 Server 8.2. DHCPv6 Server Configuration 8.2.1. Introduction 8.2.2. Lease Storage 8.2.3. Hosts Storage 8.2.4. Interface Selection 8.2.5. IPv6 Subnet Identifier 8.2.6. Unicast Traffic Support 8.2.7. Subnet and Address Pool 8.2.8. Subnet and Prefix Delegation Pools 8.2.9. Standard DHCPv6 Options 8.2.10. Custom DHCPv6 Options 8.2.11. DHCPv6 Vendor-Specific Options 8.2.12. Nested DHCPv6 Options (Custom Option Spaces) 8.2.13. Unspecified Parameters for DHCPv6 Option Configuration 8.2.14. IPv6 Subnet Selection 8.2.15. Rapid Commit 8.2.16. DHCPv6 Relays 8.2.17. Relay-Supplied Options 8.2.18. Client Classification in DHCPv6 8.2.19. DDNS for DHCPv6 8.2.20. DHCPv4-over-DHCPv6: DHCPv6 Side 8.3. Host Reservation in DHCPv6 8.3.1. Address/Prefix Reservation Types 8.3.2. Conflicts in DHCPv6 Reservations 8.3.3. Reserving a Hostname 8.3.4. Including Specific DHCPv6 Options in Reservations 8.3.5. Reserving Client Classes in DHCPv6 8.3.6. Storing Host Reservations in MySQL or PostgreSQL 8.3.7. Storing Host Reservations in CQL (Cassandra) 8.3.8. Fine Tuning DHCPv6 Host Reservation 8.4. Server Identifier in DHCPv6 8.5. Stateless DHCPv6 (Information-Request Message) 8.6. Support for RFC 7550 8.7. Using Specific Relay Agent for a Subnet 8.8. Segregating IPv6 Clients in a Cable Network 8.9. MAC/Hardware Addresses in DHCPv6 8.10. Duplicate Addresses (DECLINE Support) 8.11. Statistics in the DHCPv6 Server 8.12. Management API for the DHCPv6 Server 8.13. Supported DHCPv6 Standards 8.14. DHCPv6 Server Limitations 8.1. Starting and Stopping the DHCPv6 Server It is recommended that the Kea DHCPv6 server be started and stopped using keactrl (described in Chapter 6, Managing Kea with keactrl). However, it is also possible to run the server directly: it accepts the following command-line switches: * -c file - specifies the configuration file. This is the only mandatory switch. * -d - specifies whether the server logging should be switched to verbose mode. In verbose mode, the logging severity and debuglevel specified in the configuration file are ignored and "debug" severity and the maximum debuglevel (99) are assumed. The flag is convenient, for temporarily switching the server into maximum verbosity, e.g. when debugging. * -p port - specifies UDP port on which the server will listen. This is only useful during testing, as a DHCPv6 server listening on ports other than the standard ones will not be able to handle regular DHCPv6 queries. * -v - prints out the Kea version and exits. * -V - prints out the Kea extended version with additional parameters and exits. The listing includes the versions of the libraries dynamically linked to Kea. * -W - prints out the Kea configuration report and exits. The report is a copy of the config.report file produced by ./configure: it is embedded in the executable binary. The config.report may also be accessed more directly. The following command may be used to extract this information. The binary path may be found in the install directory or in the .libs subdirectory in the source tree. For example kea/src/bin/dhcp6/.libs/kea-dhcp6. strings path/kea-dhcp6 | sed -n 's/;;;; //p' On start-up, the server will detect available network interfaces and will attempt to open UDP sockets on all interfaces mentioned in the configuration file. Since the DHCPv6 server opens privileged ports, it requires root access. Make sure you run this daemon as root. During startup the server will attempt to create a PID file of the form: localstatedir]/[conf name].kea-dhcp6.pid where: * localstatedir: The value as passed into the build configure script. It defaults to "/usr/local/var". Note that this value may be overridden at run time by setting the environment variable KEA_PIDFILE_DIR. This is intended primarily for testing purposes. * conf name: The configuration file name used to start the server, minus all preceding path and file extension. For example, given a pathname of "/usr/local/etc/kea/myconf.txt", the portion used would be "myconf". If the file already exists and contains the PID of a live process, the server will issue a DHCP6_ALREADY_RUNNING log message and exit. It is possible, though unlikely, that the file is a remnant of a system crash and the process to which the PID belongs is unrelated to Kea. In such a case it would be necessary to manually delete the PID file. The server can be stopped using the kill command. When running in a console, the server can be shut down by pressing ctrl-c. It detects the key combination and shuts down gracefully. 8.2. DHCPv6 Server Configuration 8.2.1. Introduction This section explains how to configure the DHCPv6 server using the Kea configuration backend. (Kea configuration using any other backends is outside of scope of this document.) Before DHCPv6 is started, its configuration file has to be created. The basic configuration is as follows: { # DHCPv6 configuration starts on the next line "Dhcp6": { # First we set up global values "valid-lifetime": 4000, "renew-timer": 1000, "rebind-timer": 2000, "preferred-lifetime": 3000, # Next we setup the interfaces to be used by the server. "interfaces-config": { "interfaces": [ "eth0" ] }, # And we specify the type of lease database "lease-database": { "type": "memfile", "persist": true, "name": "/var/kea/dhcp6.leases" }, # Finally, we list the subnets from which we will be leasing addresses. "subnet6": [ { "subnet": "2001:db8:1::/64", "pools": [ { "pool": "2001:db8:1::1-2001:db8:1::ffff" } ] } ] # DHCPv6 configuration ends with the next line } } The following paragraphs provide a brief overview of the parameters in the above example together with their format. Subsequent sections of this chapter go into much greater detail for these and other parameters. The lines starting with a hash (#) are comments and are ignored by the server; they do not impact its operation in any way. The configuration starts in the first line with the initial opening curly bracket (or brace). Each configuration consists of one or more objects. In this specific example, we have only one object, called Dhcp6. This is a simplified configuration, as usually there will be additional objects, like Logging or DhcpDns, but we omit them now for clarity. The Dhcp6 configuration starts with the "Dhcp6": { line and ends with the corresponding closing brace (in the above example, the brace after the last comment). Everything defined between those lines is considered to be the Dhcp6 configuration. In the general case, the order in which those parameters appear does not matter. There are two caveats here though. The first one is to remember that the configuration file must be well formed JSON. That means that parameters for any given scope must be separated by a comma and there must not be a comma after the last parameter. When reordering a configuration file, keep in mind that moving a parameter to or from the last position in a given scope may also require moving the comma. The second caveat is that it is uncommon -- although legal JSON -- to repeat the same parameter multiple times. If that happens, the last occurrence of a given parameter in a given scope is used while all previous instances are ignored. This is unlikely to cause any confusion as there are no real life reasons to keep multiple copies of the same parameter in your configuration file. Moving onto the DHCPv6 configuration elements, the very first few elements define some global parameters. valid-lifetime defines for how long the addresses (leases) given out by the server are valid. If nothing changes, a client that got an address is allowed to use it for 4000 seconds. (Note that integer numbers are specified as is, without any quotes around them.) The address will become deprecated in 3000 seconds (clients are allowed to keep old connections, but can't use this address for creating new connections). renew-timer and rebind-timer are values that define T1 and T2 timers that govern when the client will begin the renewal and rebind procedures. The interfaces-config map specifies the server configuration concerning the network interfaces, on which the server should listen to the DHCP messages. The interfaces parameter specifies a list of network interfaces on which the server should listen. Lists are opened and closed with square brackets, with elements separated by commas. Had we wanted to listen on two interfaces, the interfaces-config would look like this: "interfaces-config": { "interfaces": [ "eth0", "eth1" ] }, The next couple of lines define the lease database, the place where the server stores its lease information. This particular example tells the server to use memfile, which is the simplest (and fastest) database backend. It uses an in-memory database and stores leases on disk in a CSV file. This is a very simple configuration. Usually the lease database configuration is more extensive and contains additional parameters. Note that lease-database is an object and opens up a new scope, using an opening brace. Its parameters (just one in this example - type) follow. Had there been more than one, they would be separated by commas. This scope is closed with a closing brace. As more parameters for the Dhcp6 definition follow, a trailing comma is present. Finally, we need to define a list of IPv6 subnets. This is the most important DHCPv6 configuration structure as the server uses that information to process clients' requests. It defines all subnets from which the server is expected to receive DHCP requests. The subnets are specified with the subnet6 parameter. It is a list, so it starts and ends with square brackets. Each subnet definition in the list has several attributes associated with it, so it is a structure and is opened and closed with braces. At minimum, a subnet definition has to have at least two parameters: subnet (that defines the whole subnet) and pools (which is a list of dynamically allocated pools that are governed by the DHCP server). The example contains a single subnet. Had more than one been defined, additional elements in the subnet6 parameter would be specified and separated by commas. For example, to define two subnets, the following syntax would be used: "subnet6": [ { "pools": [ { "pool": "2001:db8:1::/112" } ], "subnet": "2001:db8:1::/64" }, { "pools": [ { "pool": "2001:db8:2::1-2001:db8:2::ffff" } ], "subnet": "2001:db8:2::/64" } ] Note that indentation is optional and is used for aesthetic purposes only. In some cases in may be preferable to use more compact notation. After all parameters are specified, we have two contexts open: global and Dhcp6, hence we need two closing curly brackets to close them. In a real life configuration file there most likely would be additional components defined such as Logging or DhcpDdns, so the closing brace would be followed by a comma and another object definition. 8.2.2. Lease Storage All leases issued by the server are stored in the lease database. Currently there are four database backends available: memfile (which is the default backend), MySQL, PostgreSQL and Cassandra. 8.2.2.1. Memfile - Basic Storage for Leases The server is able to store lease data in different repositories. Larger deployments may elect to store leases in a database. Section 8.2.2.2, "Lease Database Configuration" describes this option. In typical smaller deployments though, the server will store lease information in a CSV file rather than a database. As well as requiring less administration, an advantage of using a file for storage is that it eliminates a dependency on third-party database software. The configuration of the file backend (Memfile) is controlled through the Dhcp6/lease-database parameters. The type parameter is mandatory and it specifies which storage for leases the server should use. The value of "memfile" indicates that the file should be used as the storage. The following list gives additional, optional, parameters that can be used to configure the Memfile backend. * persist: controls whether the new leases and updates to existing leases are written to the file. It is strongly recommended that the value of this parameter is set to true at all times, during the server's normal operation. Not writing leases to disk will mean that if a server is restarted (e.g. after a power failure), it will not know what addresses have been assigned. As a result, it may hand out addresses to new clients that are already in use. The value of false is mostly useful for performance testing purposes. The default value of the persist parameter is true, which enables writing lease updates to the lease file. * name: specifies an absolute location of the lease file in which new leases and lease updates will be recorded. The default value for this parameter is "[kea-install-dir]/var/kea/kea-leases6.csv" . * lfc-interval: specifies the interval in seconds, at which the server will perform a lease file cleanup (LFC). This removes redundant (historical) information from the lease file and effectively reduces the lease file size. The cleanup process is described in more detailed fashion further in this section. The default value of the lfc-interval is 0, which disables the LFC. An example configuration of the Memfile backend is presented below: "Dhcp6": { "lease-database": { "type": "memfile", "persist": true, "name": "/tmp/kea-leases6.csv", "lfc-interval": 1800 } } This configuration selects the /tmp/kea-leases6.csv as the storage for lease information and enables persistence (writing lease updates to this file). It also configures the backend perform the periodic cleanup of the lease files, executed every 30 minutes. It is important to know how the lease file contents are organized to understand why the periodic lease file cleanup is needed. Every time the server updates a lease or creates a new lease for the client, the new lease information must be recorded in the lease file. For performance reasons, the server does not update the existing client's lease in the file, as it would potentially require rewriting the entire file. Instead, it simply appends the new lease information to the end of the file: the previous lease entries for the client are not removed. When the server loads leases from the lease file, e.g. at the server startup, it assumes that the latest lease entry for the client is the valid one. The previous entries are discarded. This means that the server can re-construct the accurate information about the leases even though there may be many lease entries for each client. However, storing many entries for each client results in bloated lease file and impairs the performance of the server's startup and reconfiguration as it needs to process a larger number of lease entries. Lease file cleanup (LFC) removes all previous entries for each client and leaves only the latest ones. The interval at which the cleanup is performed is configurable, and it should be selected according to the frequency of lease renewals initiated by the clients. The more frequent the renewals, the smaller the value of lfc-interval should be. Note however, that the LFC takes time and thus it is possible (although unlikely) that new cleanup is started while the previous cleanup instance is still running, if the lfc-interval is too short. The server would recover from this by skipping the new cleanup when it detects that the previous cleanup is still in progress. But it implies that the actual cleanups will be triggered more rarely than configured. Moreover, triggering a new cleanup adds an overhead to the server which will not be able to respond to new requests for a short period of time when the new cleanup process is spawned. Therefore, it is recommended that the lfc-interval value is selected in a way that would allow for the LFC to complete the cleanup before a new cleanup is triggered. Lease file cleanup is performed by a separate process (in background) to avoid a performance impact on the server process. In order to avoid the conflicts between two processes both using the same lease files, the LFC process operates on the copy of the original lease file, rather than on the lease file used by the server to record lease updates. There are also other files being created as a side effect of the lease file cleanup. The detailed description of the LFC is located on the Kea wiki: http://kea.isc.org/wiki/LFCDesign. 8.2.2.2. Lease Database Configuration Note Lease database access information must be configured for the DHCPv6 server, even if it has already been configured for the DHCPv4 server. The servers store their information independently, so each server can use a separate database or both servers can use the same database. Lease database configuration is controlled through the Dhcp6/lease-database parameters. The type of the database must be set to "memfile", "mysql", "postgresql" or "cql", e.g. "Dhcp6": { "lease-database": { "type": "mysql", ... }, ... } Next, the name of the database is to hold the leases must be set: this is the name used when the database was created (see Section 4.3.2.1, "First Time Creation of the MySQL Database", Section 4.3.3.1, "First Time Creation of the PostgreSQL Database" or Section 4.3.4.1, "First Time Creation of the Cassandra Database"). "Dhcp6": { "lease-database": { "name": "database-name" , ... }, ... } If the database is located on a different system to the DHCPv6 server, the database host name must also be specified. (It should be noted that this configuration may have a severe impact on server performance.): "Dhcp6": { "lease-database": { "host": remote-host-name, ... }, ... } The usual state of affairs will be to have the database on the same machine as the DHCPv6 server. In this case, set the value to the empty string: "Dhcp6": { "lease-database": { "host" : "", ... }, ... } Should the database be located on a different system, you may need to specify a longer interval for the connection timeout: "Dhcp6": { "lease-database": { "connect-timeout" : timeout-in-seconds, ... }, ... } The default value of five seconds should be more than adequate for local connections. If a timeout is given though, it should be an integer greater than zero. Finally, the credentials of the account under which the server will access the database should be set: "Dhcp6": { "lease-database": { "user": "user-name", "password": "password", ... }, ... } If there is no password to the account, set the password to the empty string "". (This is also the default.) 8.2.3. Hosts Storage Kea is also able to store information about host reservations in the database. The hosts database configuration uses the same syntax as the lease database. In fact, a Kea server opens independent connections for each purpose, be it lease or hosts information. This arrangement gives the most flexibility. Kea can be used to keep leases and host reservations separately, but can also point to the same database. Currently the supported hosts database types are MySQL and PostgreSQL. The Cassandra backend does not support host reservations yet. Please note that usage of hosts storage is optional. A user can define all host reservations in the configuration file. That is the recommended way if the number of reservations is small. However, when the number of reservations grows it's more convenient to use host storage. Please note that both storage methods (configuration file and one of the supported databases) can be used together. If hosts are defined in both places, the definitions from the configuration file are checked first and external storage is checked later, if necessary. 8.2.3.1. DHCPv6 Hosts Database Configuration Hosts database configuration is controlled through the Dhcp6/hosts-database parameters. If enabled, the type of the database must be set to "mysql" or "postgresql". Other hosts backends may be added in later version of Kea. "Dhcp6": { "hosts-database": { "type": "mysql", ... }, ... } Next, the name of the database to hold the reservations must be set: this is the name used when the database was created (see Section 4.3, "Supported Databases" for instructions how to setup desired database type). "Dhcp6": { "hosts-database": { "name": "database-name" , ... }, ... } If the database is located on a different system than the DHCPv6 server, the database host name must also be specified. (Again it should be noted that this configuration may have a severe impact on server performance): "Dhcp6": { "hosts-database": { "host": remote-host-name, ... }, ... } The usual state of affairs will be to have the database on the same machine as the DHCPv6 server. In this case, set the value to the empty string: "Dhcp6": { "hosts-database": { "host" : "", ... }, ... } Finally, the credentials of the account under which the server will access the database should be set: "Dhcp6": { "hosts-database": { "user": "user-name", "password": "password", ... }, ... } If there is no password to the account, set the password to the empty string "". (This is also the default.) 8.2.3.2. Using Read-Only Databases for Host Reservations In some deployments the database user whose name is specified in the database backend configuration may not have write privileges to the database. This is often required by the policy within a given network to secure the data from being unintentionally modified. In many cases administrators have inventory databases deployed, which contain substantially more information about the hosts than static reservations assigned to them. The inventory database can be used to create a view of a Kea hosts database and such view is often read only. Kea host database backends operate with an implicit configuration to both read from and write to the database. If the database user does not have write access to the host database, the backend will fail to start and the server will refuse to start (or reconfigure). However, if access to a read only host database is required for retrieving reservations for clients and/or assign specific addresses and options, it is possible to explicitly configure Kea to start in "read-only" mode. This is controlled by the readonly boolean parameter as follows: "Dhcp6": { "hosts-database": { "readonly": true, ... }, ... } Setting this parameter to false would configure the database backend to operate in "read-write" mode, which is also a default configuration if the parameter is not specified. Note The readonly parameter is currently only supported for MySQL and PostgreSQL databases. 8.2.4. Interface Selection The DHCPv6 server has to be configured to listen on specific network interfaces. The simplest network interface configuration instructs the server to listen on all available interfaces: "Dhcp6": { "interfaces-config": { "interfaces": [ "*" ] } ... } The asterisk plays the role of a wildcard and means "listen on all interfaces". However, it is usually a good idea to explicitly specify interface names: "Dhcp6": { "interfaces-config": { "interfaces": [ "eth1", "eth3" ] }, ... } It is possible to use wildcard interface name (asterisk) concurrently with the actual interface names: "Dhcp6": { "interfaces-config": { "interfaces": [ "eth1", "eth3", "*" ] }, ... } It is anticipated that this will form of usage only be used where it is desired to temporarily override a list of interface names and listen on all interfaces. 8.2.5. IPv6 Subnet Identifier The subnet identifier is a unique number associated with a particular subnet. In principle, it is used to associate clients' leases with their respective subnets. When a subnet identifier is not specified for a subnet being configured, it will be automatically assigned by the configuration mechanism. The identifiers are assigned from 1 and are monotonically increased for each subsequent subnet: 1, 2, 3 .... If there are multiple subnets configured with auto-generated identifiers and one of them is removed, the subnet identifiers may be renumbered. For example: if there are four subnets and the third is removed the last subnet will be assigned the identifier that the third subnet had before removal. As a result, the leases stored in the lease database for subnet 3 are now associated with subnet 4, something that may have unexpected consequences. It is planned to implement a mechanism to preserve auto-generated subnet ids in a future version of Kea. However, the only remedy for this issue at present is to manually specify a unique identifier for each subnet. The following configuration will assign the specified subnet identifier to the newly configured subnet: "Dhcp6": { "subnet6": [ { "subnet": "2001:db8:1::/64", "id": 1024, ... } ] } This identifier will not change for this subnet unless the "id" parameter is removed or set to 0. The value of 0 forces auto-generation of the subnet identifier. 8.2.6. Unicast Traffic Support When the DHCPv6 server starts, by default it listens to the DHCP traffic sent to multicast address ff02::1:2 on each interface that it is configured to listen on (see Section 8.2.4, "Interface Selection"). In some cases it is useful to configure a server to handle incoming traffic sent to the global unicast addresses as well. The most common reason for this is to have relays send their traffic to the server directly. To configure the server to listen on a specific unicast address, nn interface name can be optionally followed by a slash, followed by the global unicast address on which the server should listen. The server listens to this address in addition to normal link-local binding and listening on ff02::1:2 address. The sample configuration below shows how to listen on 2001:db8::1 (a global address) configured on the eth1 interface. "Dhcp6": { "interfaces-config": { "interfaces": [ "eth1/2001:db8::1" ] }, ... "option-data": [ { "name": "unicast", "data": "2001:db8::1" } ], ... } This configuration will cause the server to listen on eth1 on the link-local address, the multicast group (ff02::1:2) and 2001:db8::1. Usually unicast support is associated with a server unicast option which allows clients to send unicast messages to the server. The example above includes a server unicast option specification which will cause the client to send messages to the specified unicast address. It is possible to mix interface names, wildcards and interface name/addresses in the list of interfaces. It is not possible however to specify more than one unicast address on a given interface. Care should be taken to specify proper unicast addresses. The server will attempt to bind to the addresses specified without any additional checks. This approach has selected on purpose to allow the software to communicate over uncommon addresses if so desired. 8.2.7. Subnet and Address Pool The main role of a DHCPv6 server is address assignment. For this, the server has to be configured with at least one subnet and one pool of dynamic addresses to be managed. For example, assume that the server is connected to a network segment that uses the 2001:db8:1::/64 prefix. The Administrator of that network has decided that addresses from range 2001:db8:1::1 to 2001:db8:1::ffff are going to be managed by the Dhcp6 server. Such a configuration can be achieved in the following way: "Dhcp6": { "subnet6": [ { "subnet": "2001:db8:1::/64", "pools": [ { "pool": "2001:db8:1::1-2001:db8:1::ffff" } ], ... } ] } Note that subnet is defined as a simple string, but the pools parameter is actually a list of pools: for this reason, the pool definition is enclosed in square brackets, even though only one range of addresses is specified. Each pool is a structure that contains the parameters that describe a single pool. Currently there is only one parameter, pool, which gives the range of addresses in the pool. Additional parameters will be added in future releases of Kea. It is possible to define more than one pool in a subnet: continuing the previous example, further assume that 2001:db8:1:0:5::/80 should also be managed by the server. It could be written as 2001:db8:1:0:5:: to 2001:db8:1::5:ffff:ffff:ffff, but typing so many 'f's is cumbersome. It can be expressed more simply as 2001:db8:1:0:5::/80. Both formats are supported by Dhcp6 and can be mixed in the pool list. For example, one could define the following pools: "Dhcp6": { "subnet6": [ { "subnet": "2001:db8:1::/64", "pools": [ { "pool": "2001:db8:1::1-2001:db8:1::ffff" }, { "pool": "2001:db8:1:05::/80" } ], ... } ] } White space in pool definitions is ignored, so spaces before and after the hyphen are optional. They can be used to improve readability. The number of pools is not limited, but for performance reasons it is recommended to use as few as possible. The server may be configured to serve more than one subnet. To add a second subnet, use a command similar to the following: "Dhcp6": { "subnet6": [ { "subnet": "2001:db8:1::/64", "pools": [ { "pool": "2001:db8:1::1-2001:db8:1::ffff" } ] }, { "subnet": "2001:db8:2::/64", "pools": [ { "pool": "2001:db8:2::/64" } ] }, ... ] } In this example, we allow the server to dynamically assign all addresses available in the whole subnet. Although rather wasteful, it is certainly a valid configuration to dedicate the whole /64 subnet for that purpose. Note that the Kea server does not preallocate the leases, so there is no danger in using gigantic address pools. When configuring a DHCPv6 server using prefix/length notation, please pay attention to the boundary values. When specifying that the server can use a given pool, it will also be able to allocate the first (typically network address) address from that pool. For example, for pool 2001:db8:2::/64 the 2001:db8:2:: address may be assigned as well. If you want to avoid this, use the "min-max" notation. 8.2.8. Subnet and Prefix Delegation Pools Subnets may also be configured to delegate prefixes, as defined in RFC 3633. A subnet may have one or more prefix delegation pools. Each pool has a prefixed address, which is specified as a prefix (prefix) and a prefix length (prefix-len), as well as a delegated prefix length (delegated-len). The delegated length must not be shorter (that is it must be numerically greater or equal) than the prefix length. If both the delegated and prefix lengths are equal, the server will be able to delegate only one prefix. The delegated prefix does not have to match the subnet prefix. Below is a sample subnet configuration which enables prefix delegation for the subnet: "Dhcp6": { "subnet6": [ { "subnet": "2001:d8b:1::/64", "pd-pools": [ { "prefix": "3000:1::", "prefix-len": 64, "delegated-len": 96 } ] } ], ... } 8.2.9. Standard DHCPv6 Options One of the major features of a DHCPv6 server is to provide configuration options to clients. Although there are several options that require special behavior, most options are sent by the server only if the client explicitly requests them. The following example shows how to configure DNS servers, one of the most frequently used options. Options specified in this way are considered global and apply to all configured subnets. "Dhcp6": { "option-data": [ { "name": "dns-servers", "code": 23, "space": "dhcp6", "csv-format": true, "data": "2001:db8::cafe, 2001:db8::babe" }, ... ] } The option-data line creates a new entry in the option-data table. This table contains information on all global options that the server is supposed to configure in all subnets. The name line specifies the option name. (For a complete list of currently supported names, see Table 8.1, "List of Standard DHCPv6 Options".) The next line specifies the option code, which must match one of the values from that list. The line beginning with space specifies the option space, which must always be set to "dhcp6" as these are standard DHCPv6 options. For other name spaces, including custom option spaces, see Section 8.2.12, "Nested DHCPv6 Options (Custom Option Spaces)". The following line specifies the format in which the data will be entered: use of CSV (comma separated values) is recommended. Finally, the data line gives the actual value to be sent to clients. Data is specified as normal text, with values separated by commas if more than one value is allowed. Options can also be configured as hexadecimal values. If "csv-format" is set to false, the option data must be specified as a string of hexadecimal numbers. The following commands configure the DNS-SERVERS option for all subnets with the following addresses: 2001:db8:1::cafe and 2001:db8:1::babe. "Dhcp6": { "option-data": [ { "name": "dns-servers", "code": 23, "space": "dhcp6", "csv-format": false, "data": "2001 0DB8 0001 0000 0000 0000 0000 CAFE 2001 0DB8 0001 0000 0000 0000 0000 BABE" }, ... ] } Note The value for the setting of the "data" element is split across two lines in this example for clarity: when entering the command, the whole string should be entered on the same line. Care should be taken to use proper encoding when using hexadecimal format as Kea's ability to validate data correctness in hexadecimal is limited. Most of the parameters in the "option-data" structure are optional and can be omitted in some circumstances as discussed in the Section 8.2.13, "Unspecified Parameters for DHCPv6 Option Configuration". It is possible to override options on a per-subnet basis. If clients connected to most of your subnets are expected to get the same values of a given option, you should use global options: you can then override specific values for a small number of subnets. On the other hand, if you use different values in each subnet, it does not make sense to specify global option values (Dhcp6/option-data), rather you should set only subnet-specific values (Dhcp6/subnet[X]/option-data[Y]). The following commands override the global DNS servers option for a particular subnet, setting a single DNS server with address 2001:db8:1::3. "Dhcp6": { "subnet6": [ { "option-data": [ { "name": "dns-servers", "code": 23, "space": "dhcp6", "csv-format": true, "data": "2001:db8:1::3" }, ... ], ... }, ... ], ... } The currently supported standard DHCPv6 options are listed in Table 8.1, "List of Standard DHCPv6 Options". The "Name" and "Code" are the values that should be used as a name in the option-data structures. "Type" designates the format of the data: the meanings of the various types is given in Table 7.3, "List of standard DHCP option types". Experimental options (like standard options but with a code which was not assigned by IANA) are listed in Table 8.2, "List of Experimental DHCPv6 Options". Some options are designated as arrays, which means that more than one value is allowed in such an option. For example the option dns-servers allows the specification of more than one IPv6 address, allowing clients to obtain the addresses of multiple DNS servers. The Section 8.2.10, "Custom DHCPv6 Options" describes the configuration syntax to create custom option definitions (formats). It is generally not allowed to create custom definitions for standard options, even if the definition being created matches the actual option format defined in the RFCs. There is an exception from this rule for standard options for which Kea does not yes provide a definition. In order to use such options, a server administrator must create a definition as described in Section 8.2.10, "Custom DHCPv6 Options" in the 'dhcp6' option space. This definition should match the option format described in the relevant RFC but the configuration mechanism would allow any option format as it has no means to validate the format at the moment. Table 8.1. List of Standard DHCPv6 Options +------------------------------------------------------------------------+ | Name | Code | Type | Array? | |--------------------------+------+-----------------------------+--------| | preference | 7 | uint8 | false | |--------------------------+------+-----------------------------+--------| | unicast | 12 | ipv6-address | false | |--------------------------+------+-----------------------------+--------| | vendor-opts | 17 | uint32 | false | |--------------------------+------+-----------------------------+--------| | sip-server-dns | 21 | fqdn | true | |--------------------------+------+-----------------------------+--------| | sip-server-addr | 22 | ipv6-address | true | |--------------------------+------+-----------------------------+--------| | dns-servers | 23 | ipv6-address | true | |--------------------------+------+-----------------------------+--------| | domain-search | 24 | fqdn | true | |--------------------------+------+-----------------------------+--------| | nis-servers | 27 | ipv6-address | true | |--------------------------+------+-----------------------------+--------| | nisp-servers | 28 | ipv6-address | true | |--------------------------+------+-----------------------------+--------| | nis-domain-name | 29 | fqdn | true | |--------------------------+------+-----------------------------+--------| | nisp-domain-name | 30 | fqdn | true | |--------------------------+------+-----------------------------+--------| | sntp-servers | 31 | ipv6-address | true | |--------------------------+------+-----------------------------+--------| | information-refresh-time | 32 | uint32 | false | |--------------------------+------+-----------------------------+--------| | bcmcs-server-dns | 33 | fqdn | true | |--------------------------+------+-----------------------------+--------| | bcmcs-server-addr | 34 | ipv6-address | true | |--------------------------+------+-----------------------------+--------| | geoconf-civic | 36 | record (uint8, uint16, | false | | | | binary) | | |--------------------------+------+-----------------------------+--------| | remote-id | 37 | record (uint32, binary) | false | |--------------------------+------+-----------------------------+--------| | subscriber-id | 38 | binary | false | |--------------------------+------+-----------------------------+--------| | client-fqdn | 39 | record (uint8, fqdn) | false | |--------------------------+------+-----------------------------+--------| | pana-agent | 40 | ipv6-address | true | |--------------------------+------+-----------------------------+--------| | new-posix-timezone | 41 | string | false | |--------------------------+------+-----------------------------+--------| | new-tzdb-timezone | 42 | string | false | |--------------------------+------+-----------------------------+--------| | ero | 43 | uint16 | true | |--------------------------+------+-----------------------------+--------| | lq-query | 44 | record (uint8, | false | | | | ipv6-address) | | |--------------------------+------+-----------------------------+--------| | client-data | 45 | empty | false | |--------------------------+------+-----------------------------+--------| | clt-time | 46 | uint32 | false | |--------------------------+------+-----------------------------+--------| | lq-relay-data | 47 | record (ipv6-address, | false | | | | binary) | | |--------------------------+------+-----------------------------+--------| | lq-client-link | 48 | ipv6-address | true | |--------------------------+------+-----------------------------+--------| | bootfile-url | 59 | string | false | |--------------------------+------+-----------------------------+--------| | bootfile-param | 60 | binary | false | |--------------------------+------+-----------------------------+--------| | client-arch-type | 61 | uint16 | true | |--------------------------+------+-----------------------------+--------| | nii | 62 | record (uint8, uint8, | false | | | | uint8) | | |--------------------------+------+-----------------------------+--------| | erp-local-domain-name | 65 | fqdn | false | |--------------------------+------+-----------------------------+--------| | rsoo | 66 | empty | false | |--------------------------+------+-----------------------------+--------| | client-linklayer-addr | 79 | binary | false | |--------------------------+------+-----------------------------+--------| | dhcp4o6-server-addr | 88 | ipv6-address | true | +------------------------------------------------------------------------+ Table 8.2. List of Experimental DHCPv6 Options +-------------------------------------------------------------+ | Name | Code | Type | Array? | |-------------+------+-------------------------------+--------| | public-key | 701 | binary | false | |-------------+------+-------------------------------+--------| | certificate | 702 | binary | false | |-------------+------+-------------------------------+--------| | signature | 703 | record (uint8, uint8, binary) | false | |-------------+------+-------------------------------+--------| | timestamp | 704 | binary | false | +-------------------------------------------------------------+ 8.2.10. Custom DHCPv6 Options It is possible to define options in addition to the standard ones. Assume that we want to define a new DHCPv6 option called "foo" which will have code 100 and which will convey a single unsigned 32 bit integer value. We can define such an option by using the following commands: "Dhcp6": { "option-def": [ { "name": "foo", "code": 100, "type": "uint32", "array": false, "record-types": "", "space": "dhcp6", "encapsulate": "" }, ... ], ... } The "false" value of the array parameter determines that the option does NOT comprise an array of "uint32" values but rather a single value. Two other parameters have been left blank: record-types and encapsulate. The former specifies the comma separated list of option data fields if the option comprises a record of data fields. The record-types value should be non-empty if the type is set to "record". Otherwise it must be left blank. The latter parameter specifies the name of the option space being encapsulated by the particular option. If the particular option does not encapsulate any option space it should be left blank. Note that the above example only defines the format of the new option, it does not set its value(s). The name, code and type parameters are required, all others are optional. The array default value is false. The record-types and encapsulate default values are blank (i.e. ""). The default space is "dhcp6". Once the new option format is defined, its value is set in the same way as for a standard option. For example the following commands set a global value that applies to all subnets. "Dhcp6": { "option-data": [ { "name": "foo", "code": 100, "space": "dhcp6", "csv-format": true, "data": "12345" }, ... ], ... } New options can take more complex forms than simple use of primitives (uint8, string, ipv6-address etc): it is possible to define an option comprising a number of existing primitives. For example, assume we want to define a new option that will consist of an IPv6 address, followed by an unsigned 16 bit integer, followed by a boolean value, followed by a text string. Such an option could be defined in the following way: "Dhcp6": { "option-def": [ { "name": "bar", "code": 101, "space": "dhcp6", "type": "record", "array": false, "record-types": "ipv6-address, uint16, boolean, string", "encapsulate": "" }, ... ], ... } The "type" is set to "record" to indicate that the option contains multiple values of different types. These types are given as a comma-separated list in the "record-types" field and should be those listed in Table 7.3, "List of standard DHCP option types". The values of the option are set as follows: "Dhcp6": { "option-data": [ { "name": "bar", "space": "dhcp6", "code": 101, "csv-format": true, "data": "2001:db8:1::10, 123, false, Hello World" } ], ... } csv-format is set true to indicate that the data field comprises a command-separated list of values. The values in the "data" must correspond to the types set in the "record-types" field of the option definition. Note In the general case, boolean values are specified as true or false, without quotes. Some specific boolean parameters may accept also "true", "false", 0, 1, "0" and "1". Future versions of Kea will accept all those values for all boolean parameters. 8.2.11. DHCPv6 Vendor-Specific Options Currently there are two option spaces defined for the DHCPv6 daemon: "dhcp6" (for top level DHCPv6 options) and "vendor-opts-space", which is empty by default, but in which options can be defined. Those options will be carried in the Vendor-Specific Information option (code 17). The following examples show how to define an option "foo" with code 1 that consists of an IPv6 address, an unsigned 16 bit integer and a string. The "foo" option is conveyed in a Vendor-Specific Information option. This option comprises a single uint32 value that is set to "12345". The sub-option "foo" follows the data field holding this value. "Dhcp6": { "option-def": [ { "name": "foo", "code": 1, "space": "vendor-opts-space", "type": "record", "array": false, "record-types": "ipv6-address, uint16, string", "encapsulate": "" } ], ... } (Note that the option space is set to vendor-opts-space.) Once the option format is defined, the next step is to define actual values for that option: "Dhcp6": { "option-data": [ { "name": "foo", "space": "vendor-opts-space", "data": "2001:db8:1::10, 123, Hello World" }, ... ], ... } We should also define a value (enterprise-number) for the Vendor-specific Information option, that conveys our option "foo". "Dhcp6": { "option-data": [ ..., { "name": "vendor-opts", "data": "12345" } ], ... } Alternatively, the option can be specified using its code. "Dhcp6": { "option-data": [ ..., { "code": 17, "data": "12345" } ], ... } 8.2.12. Nested DHCPv6 Options (Custom Option Spaces) It is sometimes useful to define completely new option spaces. This is useful if the user wants their new option to convey sub-options that use a separate numbering scheme, for example sub-options with codes 1 and 2. Those option codes conflict with standard DHCPv6 options, so a separate option space must be defined. Note that it is not required to create a new option space when defining sub-options for a standard option because it is created by default if the standard option is meant to convey any sub-options (see Section 8.2.11, "DHCPv6 Vendor-Specific Options"). Assume that we want to have a DHCPv6 option called "container" with code 102 that conveys two sub-options with codes 1 and 2. First we need to define the new sub-options: "Dhcp6": { "option-def": [ { "name": "subopt1", "code": 1, "space": "isc", "type": "ipv6-address", "record-types": "", "array": false, "encapsulate": "" }, { "name": "subopt2", "code": 2, "space": "isc", "type": "string", "record-types": "", "array": false "encapsulate": "" } ], ... } Note that we have defined the options to belong to a new option space (in this case, "isc"). The next step is to define a regular DHCPv6 option and specify that it should include options from the isc option space: "Dhcp6": { "option-def": [ ..., { "name": "container", "code": 102, "space": "dhcp6", "type": "empty", "array": false, "record-types": "", "encapsulate": "isc" } ], ... } The name of the option space in which the sub-options are defined is set in the encapsulate field. The type field is set to empty which limits this option to only carrying data in sub-options. Finally, we can set values for the new options: "Dhcp6": { "option-data": [ { "name": "subopt1", "code": 1, "space": "isc", "data": "2001:db8::abcd" }, } "name": "subopt2", "code": 2, "space": "isc", "data": "Hello world" }, { "name": "container", "code": 102, "space": "dhcp6" } ], ... } Note that it is possible to create an option which carries some data in addition to the sub-options defined in the encapsulated option space. For example, if the "container" option from the previous example was required to carry an uint16 value as well as the sub-options, the "type" value would have to be set to "uint16" in the option definition. (Such an option would then have the following data structure: DHCP header, uint16 value, sub-options.) The value specified with the "data" parameter -- which should be a valid integer enclosed in quotes, e.g. "123" -- would then be assigned to the uint16 field in the "container" option. 8.2.13. Unspecified Parameters for DHCPv6 Option Configuration In many cases it is not required to specify all parameters for an option configuration and the default values can be used. However, it is important to understand the implications of not specifying some of them as it may result in configuration errors. The list below explains the behavior of the server when a particular parameter is not explicitly specified: * name - the server requires an option name or option code to identify an option. If this parameter is unspecified, the option code must be specified. * code - the server requires an option name or option code to identify an option. This parameter may be left unspecified if the name parameter is specified. However, this also requires that the particular option has its definition (it is either a standard option or an administrator created a definition for the option using an 'option-def' structure), as the option definition associates an option with a particular name. It is possible to configure an option for which there is no definition (unspecified option format). Configuration of such options requires the use of option code. * space - if the option space is unspecified it will default to 'dhcp6' which is an option space holding DHCPv6 standard options. * data - if the option data is unspecified it defaults to an empty value. The empty value is mostly used for the options which have no payload (boolean options), but it is legal to specify empty values for some options which carry variable length data and which spec allows for the length of 0. For such options, the data parameter may be omitted in the configuration. * csv-format - if this value is not specified and the definition for the particular option exists, the server will assume that the option data is specified as a list of comma separated values to be assigned to individual fields of the DHCP option. If the definition does not exist for this option, the server will assume that the data parameter contains the option payload in the binary format (represented as a string of hexadecimal digits). Note that not specifying this parameter doesn't imply that it defaults to a fixed value, but the configuration data interpretation also depends on the presence of the option definition. An administrator must be aware if the definition for the particular option exists when this parameter is not specified. It is generally recommended to not specify this parameter only for the options for which the definition exists, e.g. standard options. Setting csv-format to an explicit value will cause the server to strictly check the format of the option data specified. 8.2.14. IPv6 Subnet Selection The DHCPv6 server may receive requests from local (connected to the same subnet as the server) and remote (connecting via relays) clients. As the server may have many subnet configurations defined, it must select an appropriate subnet for a given request. The server can not assume which of the configured subnets are local. In IPv4 it is possible as there is a reasonable expectation that the server will have a (global) IPv4 address configured on the interface, and can use that information to detect whether a subnet is local or not. That assumption is not true in IPv6: the DHCPv6 server must be able to operate while only using link-local addresses. Therefore an optional interface parameter is available within a subnet definition to designate that a given subnet is local, i.e. reachable directly over the specified interface. For example the server that is intended to serve a local subnet over eth0 may be configured as follows: "Dhcp6": { "subnet6": [ { "subnet": "2001:db8:beef::/48", "pools": [ { "pool": "2001:db8:beef::/48" } ], "interface": "eth0" } ], ... } 8.2.15. Rapid Commit The Rapid Commit option, described in RFC 3315, is supported by the Kea DHCPv6 server. However, support is disabled by default for all subnets. It can be enabled for a particular subnet using the rapid-commit parameter as shown below: "Dhcp6": { "subnet6": [ { "subnet": "2001:db8:beef::/48", "rapid-commit": true, "pools": [ { "pool": "2001:db8:beef::1-2001:db8:beef::10" } ], } ], ... } This setting only affects the subnet for which the rapid-commit is set to true. For clients connected to other subnets, the server will ignore the Rapid Commit option sent by the client and will follow the 4-way exchange procedure, i.e. respond with an Advertise for a Solicit containing a Rapid Commit option. 8.2.16. DHCPv6 Relays A DHCPv6 server with multiple subnets defined must select the appropriate subnet when it receives a request from a client. For clients connected via relays, two mechanisms are used: The first uses the linkaddr field in the RELAY_FORW message. The name of this field is somewhat misleading in that it does not contain a link-layer address: instead, it holds an address (typically a global address) that is used to identify a link. The DHCPv6 server checks if the address belongs to a defined subnet and, if it does, that subnet is selected for the client's request. The second mechanism is based on interface-id options. While forwarding a client's message, relays may insert an interface-id option into the message that identifies the interface on the relay that received the message. (Some relays allow configuration of that parameter, but it is sometimes hardcoded and may range from the very simple (e.g. "vlan100") to the very cryptic: one example seen on real hardware was "ISAM144|299|ipv6|nt:vp:1:110"). The server can use this information to select the appropriate subnet. The information is also returned to the relay which then knows the interface to use to transmit the response to the client. In order for this to work successfully, the relay interface IDs must be unique within the network and the server configuration must match those values. When configuring the DHCPv6 server, it should be noted that two similarly-named parameters can be configured for a subnet: * interface defines which local network interface can be used to access a given subnet. * interface-id specifies the content of the interface-id option used by relays to identify the interface on the relay to which the response packet is sent. The two are mutually exclusive: a subnet cannot be both reachable locally (direct traffic) and via relays (remote traffic). Specifying both is a configuration error and the DHCPv6 server will refuse such a configuration. The following example configuration shows how to specify an interface-id with a value of "vlan123". "Dhcp6": { "subnet6": [ { "subnet": "2001:db8:beef::/48", "pools": [ { "pool": "2001:db8:beef::/48" } ], "interface-id": "vlan123" } ], ... } 8.2.17. Relay-Supplied Options RFC 6422 defines a mechanism called Relay-Supplied DHCP Options. In certain cases relay agents are the only entities that may have specific information. They can insert options when relaying messages from the client to the server. The server will then do certain checks and copy those options to the response that will be sent to the client. There are certain conditions that must be met for the option to be included. First, the server must not provide the option itself. In other words, if both relay and server provide an option, the server always takes precedence. Second, the option must be RSOO-enabled. IANA maintains a list of RSOO-enabled options here. However, there may be cases when system administrators want to echo other options. Kea can be instructed to treat other options as RSOO-enabled. For example, to mark options 110, 120 and 130 as RSOO-enabled, the following syntax should be used: "Dhcp6": { "relay-supplied-options": [ "110", "120", "130" ], ... } As of March 2015, only option 65 is RSOO-enabled by IANA. This option will always be treated as such and there's no need to explicitly mark it. Also, when enabling standard options, it is possible to use their names, rather than option code, e.g. (e.g. use dns-servers instead of 23). See Table 8.1, "List of Standard DHCPv6 Options" for the names. In certain cases it could also work for custom options, but due to the nature of the parser code this may be unreliable and should be avoided. 8.2.18. Client Classification in DHCPv6 The DHCPv6 server includes support for client classification. For a deeper discussion of the classification process see Chapter 12, Client Classification. In certain cases it is useful to differentiate between different types of clients and treat them accordingly. It is envisaged that client classification will be used for changing the behavior of almost any part of the DHCP message processing, including the assignment of leases from different pools, the assignment of different options (or different values of the same options) etc. In the current release of the software however, there are only two mechanisms that take advantage of client classification: subnet selection and assignment of different options. Kea can be instructed to limit access to given subnets based on class information. This is particularly useful for cases where two types of devices share the same link and are expected to be served from two different subnets. The primary use case for such a scenario is cable networks. Here, there are two classes of devices: the cable modem itself, which should be handed a lease from subnet A and all other devices behind the modem that should get a lease from subnet B. That segregation is essential to prevent overly curious users from playing with their cable modems. For details on how to set up class restrictions on subnets, see Section 12.6, "Configuring Subnets With Class Information". The process of doing classification is conducted in three steps. The first step is to assess an incoming packet and assign it to zero or more classes. The second step is to choose a subnet, possibly based on the class information. The third step is to assign options again possibly based on the class information. There are two methods of doing classification. The first is automatic and relies on examining the values in the vendor class options. Information from these options is extracted and a class name is constructed from it and added to the class list for the packet. The second allows you to specify an expression that is evaluated for each packet. If the result is true the packet is a member of the class. Note Care should be taken with client classification as it is easy for clients that do not meet class criteria to be denied any service altogether. 8.2.18.1. Defining and Using Custom Classes The following example shows how to configure a class using an expression and a subnet making use of that class. This configuration defines the class named "Client_enterprise". It is comprised of all clients whose client identifiers start with the given hex string (which would indicate a DUID based on an enterprise id of 0xAABBCCDD). They will be given an address from 2001:db8:1::0 to 2001:db8:1::FFFF and the addresses of their DNS servers set to 2001:db8:0::1 and 2001:db8:2::1. "Dhcp6": { "client-classes": [ { "name": "Client_enterprise", "test": "substring(option[1].hex,0,6) == 0x0002AABBCCDD'", "option-data": [ { "name": "dns-servers", "code": 23, "space": "dhcp6", "csv-format": true, "data": "2001:db8:0::1, 2001:db8:2::1" } ] }, ... ], "subnet6": [ { "subnet": "2001:db8:1::/64", "pools": [ { "pool": "2001:db8:1::-2001:db8:1::ffff" } ], "client-class": "Client_enterprise" } ], ... } This example shows a configuration using an automatically generated "VENDOR_CLASS_" class. The Administrator of the network has decided that addresses from range 2001:db8:1::1 to 2001:db8:1::ffff are going to be managed by the Dhcp6 server and only clients belonging to the eRouter1.0 client class are allowed to use that pool. "Dhcp6": { "subnet6": [ { "subnet": "2001:db8:1::/64", "pools": [ { "pool": "2001:db8:1::-2001:db8:1::ffff" } ], "client-class": "VENDOR_CLASS_eRouter1.0" } ], ... } 8.2.19. DDNS for DHCPv6 As mentioned earlier, kea-dhcp6 can be configured to generate requests to the DHCP-DDNS server (referred to here as "D2") to update DNS entries. These requests are known as NameChangeRequests or NCRs. Each NCR contains the following information: 1. Whether it is a request to add (update) or remove DNS entries 2. Whether the change requests forward DNS updates (AAAA records), reverse DNS updates (PTR records), or both. 3. The FQDN, lease address, and DHCID The parameters controlling the generation of NCRs for submission to D2 are contained in the dhcp-ddns section of the kea-dhcp6 configuration. The mandatory parameters for the DHCP DDNS configuration are enable-updates which is unconditionally required, and qualifying-suffix which has no default value and is required when enable-updates is set to true. The two (disabled and enabled) minimal DHCP DDNS configurations are: "Dhcp6": { "dhcp-ddns": { "enable-updates": false }, ... } and for example: "Dhcp6": { "dhcp-ddns": { "enable-updates": true, "qualifying-suffix": "example." }, ... } The default values for the "dhcp-ddns" section are as follows: * "server-ip": "127.0.0.1" * "server-port": 53001 * "sender-ip": "" * "sender-port": 0 * "max-queue-size": 1024 * "ncr-protocol": "UDP" * "ncr-format": "JSON" * "override-no-update": false * "override-client-update": false * "replace-client-name": "never" * "generated-prefix": "myhost" 8.2.19.1. DHCP-DDNS Server Connectivity In order for NCRs to reach the D2 server, kea-dhcp6 must be able to communicate with it. kea-dhcp6 uses the following configuration parameters to control this communication: * enable-updates - determines whether or not kea-dhcp6 will generate NCRs. If missing, this value is assumed to be false hence DDNS updates are disabled. To enable DDNS updates set this value to true: * server-ip - IP address on which D2 listens for requests. The default is the local loopback interface at address 127.0.0.1. You may specify either an IPv4 or IPv6 address. * server-port - port on which D2 listens for requests. The default value is 53001. * sender-ip - IP address which kea-dhcp6 should use to send requests to D2. The default value is blank which instructs kea-dhcp6 to select a suitable address. * sender-port - port which kea-dhcp6 should use to send requests to D2. The default value of 0 instructs kea-dhcp6 to select a suitable port. * max-queue-size - maximum number of requests allowed to queue waiting to be sent to D2. This value guards against requests accumulating uncontrollably if they are being generated faster than they can be delivered. If the number of requests queued for transmission reaches this value, DDNS updating will be turned off until the queue backlog has been sufficiently reduced. The intent is to allow kea-dhcp6 to continue lease operations. The default value is 1024. * ncr-protocol - socket protocol use when sending requests to D2. Currently only UDP is supported. TCP may be available in an upcoming release. * ncr-format - packet format to use when sending requests to D2. Currently only JSON format is supported. Other formats may be available in future releases. By default, kea-dhcp-ddns is assumed to running on the same machine as kea-dhcp6, and all of the default values mentioned above should be sufficient. If, however, D2 has been configured to listen on a different address or port, these values must altered accordingly. For example, if D2 has been configured to listen on 2001:db8::5 port 900, the following configuration would be required: "Dhcp6": { "dhcp-ddns": { "server-ip": "2001:db8::5", "server-port": 900, ... }, ... } 8.2.19.2. When Does kea-dhcp6 Generate a DDNS Request? kea-dhcp6 follows the behavior prescribed for DHCP servers in RFC 4704. It is important to keep in mind that kea-dhcp6 provides the initial decision making of when and what to update and forwards that information to D2 in the form of NCRs. Carrying out the actual DNS updates and dealing with such things as conflict resolution are within the purview of D2 itself (Chapter 10, The DHCP-DDNS Server). This section describes when kea-dhcp6 will generate NCRs and the configuration parameters that can be used to influence this decision. It assumes that the enable-updates parameter is true. Note Currently the interface between kea-dhcp6 and D2 only supports requests which update DNS entries for a single IP address. If a lease grants more than one address, kea-dhcp6 will create the DDNS update request for only the first of these addresses. Support for multiple address mappings may be provided in a future release. In general, kea-dhcp6 will generate DDNS update requests when: 1. A new lease is granted in response to a REQUEST 2. An existing lease is renewed but the FQDN associated with it has changed. 3. An existing lease is released in response to a RELEASE In the second case, lease renewal, two DDNS requests will be issued: one request to remove entries for the previous FQDN and a second request to add entries for the new FQDN. In the last case, a lease release, a single DDNS request to remove its entries will be made. The decision making involved when granting a new lease the first case) is more involved. When a new lease is granted, kea-dhcp6 will generate a DDNS update request only if the REQUEST contains the FQDN option (code 39). By default kea-dhcp6 will respect the FQDN N and S flags specified by the client as shown in the following table: Table 8.3. Default FQDN Flag Behavior +------------------------------------------------------------------------+ | Client | Client Intent | Server Response | Server | | Flags:N-S | | | Flags:N-S-O | |-----------+-------------------------+--------------------+-------------| | | Client wants to do | Server generates | | | 0-0 | forward updates, server | reverse-only | 1-0-0 | | | should do reverse | request | | | | updates | | | |-----------+-------------------------+--------------------+-------------| | | Server should do both | Server generates | | | 0-1 | forward and reverse | request to update | 0-1-0 | | | updates | both directions | | |-----------+-------------------------+--------------------+-------------| | 1-0 | Client wants no updates | Server does not | 1-0-0 | | | done | generate a request | | +------------------------------------------------------------------------+ The first row in the table above represents "client delegation". Here the DHCP client states that it intends to do the forward DNS updates and the server should do the reverse updates. By default, kea-dhcp6 will honor the client's wishes and generate a DDNS request to D2 to update only reverse DNS data. The parameter, override-client-update, can be used to instruct the server to override client delegation requests. When this parameter is true, kea-dhcp6 will disregard requests for client delegation and generate a DDNS request to update both forward and reverse DNS data. In this case, the N-S-O flags in the server's response to the client will be 0-1-1 respectively. (Note that the flag combination N=1, S=1 is prohibited according to RFC 4702. If such a combination is received from the client, the packet will be dropped by kea-dhcp6.) To override client delegation, set the following values in the configuration: "Dhcp6": { "dhcp-ddns": { "override-client-update": true, ... }, ... } The third row in the table above describes the case in which the client requests that no DNS updates be done. The parameter, override-no-update, can be used to instruct the server to disregard the client's wishes. When this parameter is true, kea-dhcp6 will generate DDNS update requests to kea-dhcp-ddns even if the client requests no updates be done. The N-S-O flags in the server's response to the client will be 0-1-1. To override client delegation, issue the following commands: "Dhcp6": { "dhcp-ddns": { "override-no-update": true, ... }, ... } 8.2.19.3. kea-dhcp6 Name Generation for DDNS Update Requests Each NameChangeRequest must of course include the fully qualified domain name whose DNS entries are to be affected. kea-dhcp6 can be configured to supply a portion or all of that name based upon what it receives from the client. The default rules for constructing the FQDN that will be used for DNS entries are: 1. If the DHCPREQUEST contains the client FQDN option, the candidate name is taken from there. 2. If the candidate name is a partial (i.e. unqualified) name then add a configurable suffix to the name and use the result as the FQDN. 3. If the candidate name provided is empty, generate an FQDN using a configurable prefix and suffix. 4. If the client provided neither option, then no DNS action will be taken. These rules can amended by setting the replace-client-name parameter which provides the following modes of behavior: * never - Use the name the client sent. If the client sent no name, do not generate one. This is the default mode. * always - Replace the name the client sent. If the client sent no name, generate one for the client. * when-present - Replace the name the client sent. If the client sent no name, do not generate one. * when-not-present - Use the name the client sent. If the client sent no name, generate one for the client. Note Note that formerly, this parameter was a boolean and permitted only values of true and false. Boolean values will still be accepted but may eventually be deprecated. A value of true equates to when-present, false equates to never. For example, To instruct kea-dhcp6 to always generate the FQDN for a client, set the parameter replace-client-name to always as follows: "Dhcp6": { "dhcp-ddns": { "replace-client-name": "always", ... }, ... } The prefix used in the generation of an FQDN is specified by the generated-prefix parameter. The default value is "myhost". To alter its value, simply set it to the desired string: "Dhcp6": { "dhcp-ddns": { "generated-prefix": "another.host", ... }, ... } The suffix used when generating an FQDN or when qualifying a partial name is specified by the qualifying-suffix parameter. This parameter has no default value, thus it is mandatory when DDNS updates are enabled. To set its value simply set it to the desired string: "Dhcp6": { "dhcp-ddns": { "qualifying-suffix": "foo.example.org", ... }, ... } When qualifying a partial name, kea-dhcp6 will construct a name with the format: [candidate-name].[qualifying-suffix]. where candidate-name is the partial name supplied in the REQUEST. For example, if FQDN domain name value was "some-computer" and qualifying-suffix "example.com", the generated FQDN would be: some-computer.example.com. When generating the entire name, kea-dhcp6 will construct name of the format: [generated-prefix]-[address-text].[qualifying-suffix]. where address-text is simply the lease IP address converted to a hyphenated string. For example, if lease address is 3001:1::70E, the qualifying suffix "example.com", and the default value is used for generated-prefix, the generated FQDN would be: myhost-3001-1--70E.example.com. 8.2.20. DHCPv4-over-DHCPv6: DHCPv6 Side The support of DHCPv4-over-DHCPv6 transport is described in RFC 7341 and is implemented using cooperating DHCPv4 and DHCPv6 servers. This section is about the configuration of the DHCPv6 side (the DHCPv4 side is described in Section 7.2.19, "DHCPv4-over-DHCPv6: DHCPv4 Side"). Note DHCPv4-over-DHCPv6 support is experimental and the details of the inter-process communication can change: both the DHCPv4 and DHCPv6 sides should be running the same version of Kea. There is only one specific parameter for the DHCPv6 side: dhcp4o6-port which specifies the first of the two consecutive ports of the UDP sockets used for the communication between the DHCPv6 and DHCPv4 servers (the DHCPv6 server is bound to ::1 on port and connected to ::1 on port + 1). Two other configuration entries are in general required: unicast traffic support (see Section 8.2.6, "Unicast Traffic Support") and DHCP 4o6 server address option (name "dhcp4o6-server-addr", code 88). The following configuration was used during some tests: { # DHCPv6 conf "Dhcp6": { "interfaces-config": { "interfaces": [ "eno33554984/2001:db8:1:1::1" ] }, "lease-database": { "type": "memfile", "name": "leases6" }, "preferred-lifetime": 3000, "valid-lifetime": 4000, "renew-timer": 1000, "rebind-timer": 2000, "subnet6": [ { "subnet": "2001:db8:1:1::/64", "interface": "eno33554984", "pools": [ { "pool": "2001:db8:1:1::1:0/112" } ] } ], "dhcp4o6-port": 6767, "option-data": [ { "name": "dhcp4o6-server-addr", "code": 88, "space": "dhcp6", "csv-format": true, "data": "2001:db8:1:1::1" } ] }, "Logging": { "loggers": [ { "name": "kea-dhcp6", "output_options": [ { "output": "/tmp/kea-dhcp6.log" } ], "severity": "DEBUG", "debuglevel": 0 } ] } } Note Relayed DHCPv4-QUERY DHCPv6 messages are not yet supported. 8.3. Host Reservation in DHCPv6 There are many cases where it is useful to provide a configuration on a per host basis. The most obvious one is to reserve specific, static IPv6 address or/and prefix for exclusive use by a given client (host) - returning client will get the same address or/and prefix every time and other clients will never get that address. Note that there may be cases when the new reservation has been made for the client for the address or prefix being currently in use by another client. We call this situation a "conflict". The conflicts get resolved automatically over time as described in the subsequent sections. Once conflict is resolved, the client will keep receiving the reserved configuration when it renews. Another example when the host reservations are applicable is when a host has specific requirements, e.g. a printer that needs additional DHCP options or a cable modem needs specific parameters. Yet another possible use case for host reservation is to define unique names for hosts. Hosts reservations are defined as parameters for each subnet. Each host can be identified by either DUID or its hardware/MAC address. See Section 8.9, "MAC/Hardware Addresses in DHCPv6" for details. There is an optional reservations array in the subnet6 structure. Each element in that array is a structure, that holds information about a single host. In particular, the structure has an identifier that uniquely identifies a host. In the DHCPv6 context, such an identifier is usually a DUID, but can also be a hardware or MAC address. Also, either one or more addresses or prefixes may be specified. It is possible to specify a hostname and DHCPv6 options for a given host. The following example shows how to reserve addresses and prefixes for specific hosts: "subnet6": [ { "subnet": "2001:db8:1::/48", "pools": [ { "pool": "2001:db8:1::/80" } ], "pd-pools": [ { "prefix": "2001:db8:1:8000::", "prefix-len": 56, "delegated-len": 64 } ], "reservations": [ { "duid": "01:02:03:04:05:0A:0B:0C:0D:0E", "ip-addresses": [ "2001:db8:1::100" ] }, { "hw-address": "00:01:02:03:04:05", "ip-addresses": [ "2001:db8:1::101, 2001:db8:1::102" ] }, { "duid": "01:02:03:04:05:06:07:08:09:0A", "ip-addresses": [ "2001:db8:1::103" ], "prefixes": [ "2001:db8:2:abcd::/64" ], "hostname": "foo.example.com" } ] } ] This example includes reservations for three different clients. The first reservation is made for the address 2001:db8:1::100 for a client using DUID 01:02:03:04:05:0A:0B:0C:0D:0E. The second reservation is made for two addresses 2001:db8:1::101 and 2001:db8:1::102 for a client using MAC address 00:01:02:03:04:05. Lastly, address 2001:db8:1::103 and prefix 2001:db8:2:abcd::/64 are reserved for a client using DUID 01:02:03:04:05:06:07:08:09:0A. The last reservation also assigns a hostname to this client. Note that DHCPv6 allows for a single client to lease multiple addresses and multiple prefixes at the same time. Therefore ip-addresses and prefixes are plural and are actually arrays. When the client sends multiple IA options (IA_NA or IA_PD), each reserved address or prefix is assigned to an individual IA of the appropriate type. If the number of IAs of specific type is lower than the number of reservations of that type, the number of reserved addresses or prefixes assigned to the client is equal to the number of IA_NAs or IA_PDs sent by the client, i.e. some reserved addresses or prefixes are not assigned. However, they still remain reserved for this client and the server will not assign them to any other client. If the number of IAs of specific type sent by the client is greater than the number of reserved addresses or prefixes, the server will try to assign all reserved addresses or prefixes to the individual IAs and dynamically allocate addresses or prefixes to remaining IAs. If the server cannot assign a reserved address or prefix because it is in use, the server will select the next reserved address or prefix and try to assign it to the client. If the server subsequently finds that there are no more reservations that can be assigned to the client at the moment, the server will try to assign leases dynamically. Making a reservation for a mobile host that may visit multiple subnets requires a separate host definition in each subnet it is expected to visit. It is not allowed to define multiple host definitions with the same hardware address in a single subnet. Multiple host definitions with the same hardware address are valid if each is in a different subnet. The reservation for a given host should include only one identifier, either DUID or hardware address. Defining both for the same host is considered a configuration error, but as of 1.1.0, it is not rejected. Adding host reservation incurs a performance penalty. In principle, when a server that does not support host reservation responds to a query, it needs to check whether there is a lease for a given address being considered for allocation or renewal. The server that also supports host reservation, has to perform additional checks: not only if the address is currently used (i.e. if there is a lease for it), but also whether the address could be used by someone else (i.e. if there is a reservation for it). That additional check incurs additional overhead. 8.3.1. Address/Prefix Reservation Types In a typical scenario there is an IPv6 subnet defined with a certain part of it dedicated for dynamic address allocation by the DHCPv6 server. There may be an additional address space defined for prefix delegation. Those dynamic parts are referred to as dynamic pools, address and prefix pools or simply pools. In principle, the host reservation can reserve any address or prefix that belongs to the subnet. The reservations that specify an address that belongs to configured pools are called "in-pool reservations". In contrast, those that do not belong to dynamic pools are called "out-of-pool reservations". There is no formal difference in the reservation syntax and both reservation types are handled uniformly. However, upcoming releases may offer improved performance if there are only out-of-pool reservations as the server will be able to skip reservation checks when dealing with existing leases. Therefore, system administrators are encouraged to use out-of-pool reservations if possible. 8.3.2. Conflicts in DHCPv6 Reservations As reservations and lease information are stored separately, conflicts may arise. Consider the following series of events. The server has configured the dynamic pool of addresses from the range of 2001:db8::10 to 2001:db8::20. Host A requests an address and gets 2001:db8::10. Now the system administrator decides to reserve address 2001:db8::10 for Host B. In general, reserving an address that is currently assigned to someone else is not recommended, but there are valid use cases where such an operation is warranted. The server now has a conflict to resolve. Let's analyze the situation here. If Host B boots up and request an address, the server is not able to assign the reserved address 2001:db8::10. A naive approach would to be immediately remove the lease for Host A and create a new one for Host B. That would not solve the problem, though, because as soon as Host B get the address, it will detect that the address is already in use by someone else (Host A) and would send a Decline message. Therefore in this situation, the server has to temporarily assign a different address from the dynamic pool (not matching what has been reserved) to Host B. When Host A renews its address, the server will discover that the address being renewed is now reserved for someone else (Host B). Therefore the server will remove the lease for 2001:db8::10, select a new address and create a new lease for it. It will send two addresses in its response: the old address with lifetime set to 0 to explicitly indicate that it is no longer valid and the new address with a non-zero lifetime. When Host B renews its temporarily assigned address, the server will detect that the existing lease does not match reservation, so it will release the current address Host B has and will create a new lease matching the reservation. Similar as before, the server will send two addresses: the temporarily assigned one with zeroed lifetimes, and the new one that matches reservation with proper lifetimes set. This recovery will succeed, even if other hosts will attempt to get the reserved address. Had Host C requested address 2001:db8::10 after the reservation was made, the server will propose a different address. This recovery mechanism allows the server to fully recover from a case where reservations conflict with existing leases. This procedure takes time and will roughly take as long as renew-timer value specified. The best way to avoid such recovery is to not define new reservations that conflict with existing leases. Another recommendation is to use out-of-pool reservations. If the reserved address does not belong to a pool, there is no way that other clients could get this address. 8.3.3. Reserving a Hostname When the reservation for the client includes the hostname, the server will assign this hostname to the client and send it back in the Client FQDN, if the client sent the FQDN option to the server. The reserved hostname always takes precedence over the hostname supplied by the client (via the FQDN option) or the autogenerated (from the IPv6 address) hostname. The server qualifies the reserved hostname with the value of the qualifying-suffix parameter. For example, the following subnet configuration: "subnet6": [ { "subnet": "2001:db8:1::/48", "pools": [ { "pool": "2001:db8:1::/80" } ], "reservations": [ { "duid": "01:02:03:04:05:0A:0B:0C:0D:0E", "ip-addresses": [ "2001:db8:1::100" ] "hostname": "alice-laptop" } ] } ], "dhcp-ddns": { "enable-updates": true, "qualifying-suffix": "example.isc.org." } will result in assigning the "alice-laptop.example.isc.org." hostname to the client using the DUID "01:02:03:04:05:0A:0B:0C:0D:0E". If the qualifying-suffix is not specified, the default (empty) value will be used, and in this case the value specified as a hostname will be treated as fully qualified name. Thus, by leaving the qualifying-suffix empty it is possible to qualify hostnames for the different clients with different domain names: "subnet6": [ { "subnet": "2001:db8:1::/48", "pools": [ { "pool": "2001:db8:1::/80" } ], "reservations": [ { "duid": "01:02:03:04:05:0A:0B:0C:0D:0E", "ip-addresses": [ "2001:db8:1::100" ] "hostname": "mark-desktop.example.org." } ] } ], "dhcp-ddns": { "enable-updates": true, } The above example results in the assignment of the "mark-desktop.example.org." hostname to the client using the DUID "01:02:03:04:05:0A:0B:0C:0D:0E". 8.3.4. Including Specific DHCPv6 Options in Reservations Kea 1.1.0 introduced the ability to specify options on a per host basis. The options follow the same rules as any other options. These can be standard options (see Section 8.2.9, "Standard DHCPv6 Options"), custom options (see Section 8.2.10, "Custom DHCPv6 Options") or vendor specific options (see Section 8.2.11, "DHCPv6 Vendor-Specific Options"). The following example demonstrates how standard options can be defined. "reservations": [ { "duid": "01:02:03:05:06:07:08", "ip-addresses": [ "2001:db8:1::2" ], "option-data": [ { "option-data": [ { "name": "dns-servers", "data": "3000:1::234" }, { "name": "nis-servers", "data": "3000:1::234" } } ] } ] Vendor specific options can be reserved in a similar manner: "reservations": [ { "duid": "aa:bb:cc:dd:ee:ff", "ip-addresses": [ "2001:db8::1" ], "option-data": [ { "name": "vendor-opts", "data": 4491" }, { "name": "tftp-servers", "space": "vendor-4491", "data": "3000:1::234" } ] } ] Options defined on host level have the highest priority. In other words, if there are options defined with the same type on global, subnet, class and host level, the host specific values will be used. 8.3.5. Reserving Client Classes in DHCPv6 The Section 12.4, "Using Expressions In Classification" explains how to configure the server to assign classes to a client based on the content of the options that this client sends to the server. Host reservations mechanisms also allow for the static assignment of classes to clients. The definitions of these classes are placed in the Kea configuration. The following configuration snippet shows how to specify that the client belongs to classes reserved-class1 and reserved-class2. Those classes are associated with specific options being sent to the clients which belong to them. { "client-classes": [ { "name": "reserved-class1", "option-data": [ { "name": "dns-servers", "data": "2001:db8:1::50" } ] }, { "name": "reserved-class2", "option-data": [ { "name": "nis-servers", "data": "2001:db8:1::100" } ] } ], "subnet6": [ { "pools": [ { "pool": "2001:db8:1::/64" } ], "subnet": "2001:db8:1::/48", "reservations": [ { "duid": "01:02:03:04:05:06:07:08", "client-classes": [ "reserved-class1", "reserved-class2" ] } ] } ] } Static class assignments, as shown above, can be used in conjuction with classification using expressions. 8.3.6. Storing Host Reservations in MySQL or PostgreSQL It is possible to store host reservations in MySQL or PostgreSQL. See Section 8.2.3, "Hosts Storage" for information on how to configure Kea to use reservations stored in MySQL or PostgreSQL. Kea does not provide any dedicated tools for managing reservations in a database. The Kea wiki http://kea.isc.org/wiki/HostReservationsHowTo provides detailed information and examples of how reservations can be inserted into the database. Note In Kea 1.1.0 maximum length of an option specified per host is arbitrarily set to 4096 bytes. 8.3.7. Storing Host Reservations in CQL (Cassandra) Kea currently does not support storing reservations in Cassandra (CQL). 8.3.8. Fine Tuning DHCPv6 Host Reservation The host reservation capability introduces additional restrictions for the allocation engine (the component of Kea that selects an address for a client) during lease selection and renewal. In particular, three major checks are necessary. First, when selecting a new lease, it is not sufficient for a candidate lease to not be used by another DHCP client. It also must not be reserved for another client. Second, when renewing a lease, additional check must be performed whether the address being renewed is not reserved for another client. Finally, when a host renews an address or a prefix, the server has to check whether there is a reservation for this host, so the existing (dynamically allocated) address should be revoked and the reserved one be used instead. Some of those checks may be unnecessary in certain deployments and not performing them may improve performance. The Kea server provides the reservation-mode configuration parameter to select the types of reservations allowed for the particular subnet. Each reservation type has different constraints for the checks to be performed by the server when allocating or renewing a lease for the client. Allowed values are: * all - enables all host reservation types. This is the default value. This setting is the safest and the most flexible. It allows in-pool and out-of-pool reservations. As all checks are conducted, it is also the slowest. * out-of-pool - allows only out of pool host reservations. With this setting in place, the server may assume that all host reservations are for addresses that do not belong to the dynamic pool. Therefore it can skip the reservation checks when dealing with in-pool addresses, thus improving performance. Do not use this mode if any of your reservations use in-pool address. Caution is advised when using this setting. Kea 1.1.0 does not sanity check the reservations against reservation-mode and misconfiguration may cause problems. * disabled - host reservation support is disabled. As there are no reservations, the server will skip all checks. Any reservations defined will be completely ignored. As the checks are skipped, the server may operate faster in this mode. An example configuration that disables reservation looks like follows: "Dhcp6": { "subnet6": [ { "subnet": "2001:db8:1::/64", "reservation-mode": "disabled", ... } ] } Another aspect of the host reservations are different types of identifiers. Kea 1.1.0 supports two types of identifiers in DHCPv6: hw-address and duid, but more identifier types are likely to be added in the future. This is beneficial from a usability perspective. However, there is a drawback. For each incoming packet Kea has to to extract each identifier type and then query the database to see if there is a reservation done by this particular identifier. If nothing is found, the next identifier is extracted and next query is issued. This process continues until either a reservation is found or all identifier types have been checked. Over time with an increasing number of supported identifier types, Kea would become slower and slower. To address this problem, a parameter called host-reservation-identifiers has been introduced. It takes a list of identifier types as a parameter. Kea will check only those identifier types enumerated in host-reservation-identifiers. From a performance perspective the number of identifier types should be kept to minimum, ideally limited to one. If your deployment uses several reservation types, please enumerate them from most to least frequently used as this increases the chances of Kea finding the reservation using the fewest number of queries. An example of host reservation identifiers looks as follows: "host-reservation-identifiers": [ "duid", "hw-address" ], "subnet6": [ { "subnet": "2001:db8:1::/64", ... } ] If not specified, the default value is: "host-reservation-identifiers": [ "hw-address", "duid" ] 8.4. Server Identifier in DHCPv6 The DHCPv6 protocol uses a "server identifier" (also known as a DUID) for clients to be able to discriminate between several servers present on the same link. RFC 3315 defines three DUID types: DUID-LLT, DUID-EN and DUID-LL. RFC 6355 also defines DUID-UUID. Future specifications may introduce new DUID types. The Kea DHCPv6 server generates a server identifier once, upon the first startup, and stores it in a file. This identifier isn't modified across restarts of the server and so is a stable identifier. Kea follows recommendation from RFC 3315 to use DUID-LLT as the default server identifier. However, we have received reports that some deployments require different DUID types, and there is a need to administratively select both DUID type and/or its contents. The server identifier can be configured using parameters within the server-id map element in the global scope of the Kea configuration file. The following example demonstrates how to select DUID-EN as a server identifier: "Dhcp6": { "server-id": { "type": "EN" }, ... } Currently supported values for type parameter are: "LLT", "EN" and "LL", for DUID-LLT, DUID-EN and DUID-LL respectively. When a new DUID type is selected the server will generate its value and replace any existing DUID in the file. The server will then use the new server identifier in all future interactions with the clients. Note If the new server identifier is created after some clients have obtained their leases, the clients using the old identifier will not be able to renew the leases: the server will ignore messages containing the old server identifier. Clients will continue sending Renew until they transition to the rebinding state. In this state they will start sending Rebind messages to multicast address without a server identifier. The server will respond to the Rebind messages with a new server identifier and the clients will associate the new server identifier with their leases. Although the clients will be able to keep their leases and will eventually learn the new server identifier, this will be at the cost of increased number of renewals and multicast traffic due to a need to rebind. Therefore it is recommended that modification of the server identifier type and value is avoided if the server has already assigned leases and these leases are still valid. There are cases when an administrator needs to explicitly specify a DUID value rather than allow the server to generate it. The following example demonstrates how to explicitly set all components of a DUID-LLT. "Dhcp6": { "server-id": { "type": "LLT", "htype": 8, "identifier": "A65DC7410F05", "time": 2518920166 }, ... } where: * htype is a 16-bit unsigned value specifying hardware type, * identifier is a link layer address, specified as a string of hexadecimal digits, * time is a 32-bit unsigned time value. The hexadecimal representation of the DUID generated as a result of the configuration specified above will be: 00:01:00:08:96:23:AB:E6:A6:5D:C7:41:0F:05 |type |htype| time | identifier | It is allowed to use special value of 0 for "htype" and "time", which indicates that the server should use ANY value for these components. If the server already uses a DUID-LLT it will use the values from this DUID. If the server uses a DUID of a different type or doesn't use any DUID yet, it will generate these values. Similarly, if the "identifier" is assigned an empty string, the value of the identifier will be generated. Omitting any of these parameters is equivalent to setting them to those special values. For example, the following configuration: "Dhcp6": { "server-id": { "type": "LLT", "htype": 0, "identifier": "", "time": 2518920166 }, ... } indicates that the server should use ANY link layer address and hardware type. If the server is already using DUID-LLT it will use the link layer address and hardware type from the existing DUID. If the server is not using any DUID yet, it will use link layer address and hardware type from one of the available network interfaces. The server will use an explicit value of time. If it is different than a time value present in the currently used DUID, that value will be replaced, effectively causing modification of the current server identifier. The following example demonstrates an explicit configuration of a DUID-EN: "Dhcp6": { "server-id": { "type": "EN", "enterprise-id": 2495, "identifier": "87ABEF7A5BB545" }, ... } where: * enterprise-id is a 32-bit unsigned value holding enterprise number, * identifier is a variable length identifier within DUID-EN. The hexadecimal representation of the DUID-EN created according to the configuration above is: 00:02:00:00:09:BF:87:AB:EF:7A:5B:B5:45 |type | ent-id | identifier | As in the case of the DUID-LLT, special values can be used for the configuration of the DUID-EN. If enterprise-id is 0, the server will use a value from the existing DUID-EN. If the server is not using any DUID or the existing DUID has a different type, the ISC enterprise id will be used. When an empty string is used for identifier, the identifier from the existing DUID-EN will be used. If the server is not using any DUID-EN the new 6-bytes long identifier will be generated. DUID-LL is configured in the same way as DUID-LLT with an exception that the time parameter has no effect for DUID-LL, because this DUID type only comprises a hardware type and link layer address. The following example demonstrates how to configure DUID-LL: "Dhcp6": { "server-id": { "type": "LL", "htype": 8, "identifier": "A65DC7410F05" }, ... } which will result in the following server identifier: 00:03:00:08:A6:5D:C7:41:0F:05 |type |htype| identifier | The server stores the generated server identifier in the following location: [kea-install-dir]/var/kea/kea-dhcp6-serverid. In some uncommon deployments where no stable storage is available, the server should be configured not to try to store the server identifier. This choice is controlled by the value of persist boolean parameter: "Dhcp6": { "server-id": { "type": "EN", "enterprise-id": 2495, "identifier": "87ABEF7A5BB545", "persist": false }, ... } The default value of the "persist" parameter is true which configures the server to store the server identifier on a disk. In the example above, the server is configured to not store the generated server identifier on a disk. But, if the server identifier is not modified in the configuration the same value will be used after server restart, because entire server identifier is explicitly specified in the configuration. 8.5. Stateless DHCPv6 (Information-Request Message) Typically DHCPv6 is used to assign both addresses and options. These assignments (leases) have state that changes over time, hence their name, stateful. DHCPv6 also supports a stateless mode, where clients request configuration options only. This mode is considered lightweight from the server perspective as it does not require any state tracking; hence its name. The Kea server supports stateless mode. Clients can send Information-Request messages and the server will send back answers with the requested options (providing the options are available in the server configuration). The server will attempt to use per-subnet options first. If that fails - for whatever reason - it will then try to provide options defined in the global scope. Stateless and stateful mode can be used together. No special configuration directives are required to handle this. Simply use the configuration for stateful clients and the stateless clients will get just options they requested. This usage of global options allows for an interesting case. It is possible to run a server that provides just options and no addresses or prefixes. If the options have the same value in each subnet, the configuration can define required options in the global scope and skip subnet definitions altogether. Here's a simple example of such a configuration: "Dhcp6": { "interfaces-config": { "interfaces": [ "ethX" ] }, "option-data": [ { "name": "dns-servers", "data": "2001:db8::1, 2001:db8::2" } ], "lease-database": { "type": "memfile" } } This very simple configuration will provide DNS server information to all clients in the network, regardless of their location. Note the specification of the memfile lease database: this is needed as Kea requires a lease database to be specified even if it is not used. 8.6. Support for RFC 7550 The RFC 7550 introduced some changes to the DHCPv6 protocol to resolve a few issues with the coexistence of multiple stateful options in the messages sent between the clients and servers. The typical example is when the client, such as a requesting router, requests an allocation of both addresses and prefixes when it performs the 4-way (SARR) exchange with the server. If the server is not configured to allocate any prefixes but it can allocate some addresses, it will respond with the IA_NA(s) containing allocated addresses and the IA_PD(s) containing the NoPrefixAvail status code. If the client can operate without prefixes it may transition to the 'bound' state when it sends Renew/Rebind messages to the server, according to the T1 and T2 times, to extend the lifetimes of the allocated addresses. If the client is still interested in obtaining prefixes from the server it may also include an IA_PD in the Renew/Rebind to request allocation of the prefixes. If the server still cannot allocate the prefixes, it will respond with the IA_PD(s) containing NoPrefixAvail status code. However, if the server can now allocate the prefixes it will do so, and send them in the IA_PD(s) to the client. Allocation of leases during the Renew/Rebind was not supported in the RFC 3315 and RFC 3633, and has been introduced in RFC 7550. Kea supports this new behavior and it doesn't provide any configuration mechanisms to disable it. The following are the other behaviors specified in the RFC 7550 supported by the Kea DHCPv6 server: * Set T1/T2 timers to the same value for all stateful (IA_NA and IA_PD) options to facilitate renewal of all client's leases at the same time (in a single message exchange), * NoAddrsAvail and NoPrefixAvail status codes are placed in the IA_NA and IA_PD options in the Advertise message, rather than as the top level options. 8.7. Using Specific Relay Agent for a Subnet The relay has to have an interface connected to the link on which the clients are being configured. Typically the relay has a global IPv6 address configured on the interface that belongs to the subnet from which the server will assign addresses. In the typical case, the server is able to use the IPv6 address inserted by the relay (in the link-addr field in RELAY-FORW message) to select the appropriate subnet. However, that is not always the case. The relay address may not match the subnet in certain deployments. This usually means that there is more than one subnet allocated for a given link. The two most common examples where this is the case are long lasting network renumbering (where both old and new address space is still being used) and a cable network. In a cable network both cable modems and the devices behind them are physically connected to the same link, yet they use distinct addressing. In such case, the DHCPv6 server needs additional information (like the value of interface-id option or IPv6 address inserted in the link-addr field in RELAY-FORW message) to properly select an appropriate subnet. The following example assumes that there is a subnet 2001:db8:1::/64 that is accessible via a relay that uses 3000::1 as its IPv6 address. The server will be able to select this subnet for any incoming packets that came from a relay with an address in 2001:db8:1::/64 subnet. It will also select that subnet for a relay with address 3000::1. "Dhcp6": { "subnet6": [ { "subnet": "2001:db8:1::/64", "pools": [ { "pool": "2001:db8:1::1-2001:db8:1::ffff" } ], "relay": { "ip-address": "3000::1" } } ] } 8.8. Segregating IPv6 Clients in a Cable Network In certain cases, it is useful to mix relay address information, introduced in Section 8.7, "Using Specific Relay Agent for a Subnet" with client classification, explained in Chapter 12, Client Classification. One specific example is a cable network, where typically modems get addresses from a different subnet than all devices connected behind them. Let's assume that there is one CMTS (Cable Modem Termination System) with one CM MAC (a physical link that modems are connected to). We want the modems to get addresses from the 3000::/64 subnet, while everything connected behind modems should get addresses from another subnet (2001:db8:1::/64). The CMTS that acts as a relay an uses address 3000::1. The following configuration can serve that configuration: "Dhcp6": { "subnet6": [ { "subnet": "3000::/64", "pools": [ { "pool": "3000::2 - 3000::ffff" } ], "client-class": "VENDOR_CLASS_docsis3.0", "relay": { "ip-address": "3000::1" } }, { "subnet": "2001:db8:1::/64", "pools": [ { "pool": "2001:db8:1::1-2001:db8:1::ffff" } ], "relay": { "ip-address": "3000::1" } } ] } 8.9. MAC/Hardware Addresses in DHCPv6 MAC/hardware addresses are available in DHCPv4 messages from the clients and administrators frequently use that information to perform certain tasks, like per host configuration, address reservation for specific MAC addresses and other. Unfortunately, the DHCPv6 protocol does not provide any completely reliable way to retrieve that information. To mitigate that issue a number of mechanisms have been implemented in Kea that attempt to gather it. Each of those mechanisms works in certain cases, but may fail in other cases. Whether the mechanism works or not in the particular deployment is somewhat dependent on the network topology and the technologies used. Kea allows configuration of which of the supported methods should be used and in what order. This configuration may be considered a fine tuning of the DHCP deployment. In a typical deployment the default value of "any" is sufficient and there is no need to select specific methods. Changing the value of this parameter is the most useful in cases when an administrator wants to disable certain method, e.g. if the administrator trusts the network infrastructure more than the information provided by the clients themselves, the administrator may prefer information provided by the relays over that provided by the clients. The configuration is controlled by the mac-sourcesparameter as follows: "Dhcp6": { "mac-sources": [ "method1", "method2", "method3", ... ], "subnet6": [ ... ], ... } When not specified, a special value of "any" is used, which instructs the server to attempt to use all the methods in sequence and use value returned by the first one that succeeds. Supported methods are: * any - Not an actual method, just a keyword that instructs Kea to try all other methods and use the first one that succeeds. This is the default operation if no mac-sources are defined. * raw - In principle, a DHCPv6 server could use raw sockets to receive incoming traffic and extract MAC/hardware address information. This is currently not implemented for DHCPv6 and this value has no effect. * duid - DHCPv6 uses DUID identifiers instead of MAC addresses. There are currently four DUID types defined, with two of them (DUID-LLT, which is the default one and DUID-LL) convey MAC address information. Although RFC 3315 forbids it, it is possible to parse those DUIDs and extract necessary information from them. This method is not completely reliable, as clients may use other DUID types, namely DUID-EN or DUID-UUID. * ipv6-link-local - Another possible acquisition method comes from the source IPv6 address. In typical usage, clients are sending their packets from IPv6 link-local addresses. There is a good chance that those addresses are based on EUI-64, which contains MAC address. This method is not completely reliable, as clients may use other link-local address types. In particular, privacy extensions, defined in RFC 4941, do not use MAC addresses. Also note that successful extraction requires that the address's u-bit must be set to 1 and its g-bit set to 0, indicating that it is an interface identifier as per RFC 2373, section 2.5.1. * client-link-addr-option - One extension defined to alleviate missing MAC issues is client link-layer address option, defined in RFC 6939. This is an option that is inserted by a relay and contains information about client's MAC address. This method requires a relay agent that supports the option and is configured to insert it. This method is useless for directly connected clients. This parameter can also be specified as rfc6939, which is an alias for client-link-addr-option. * remote-id - RFC 4649 defines a remote-id option that is inserted by a relay agent. Depending on the relay agent configuration, the inserted option may convey the client's MAC address information. This parameter can also be specified as rfc4649, which is an alias for remote-id. * subscriber-id - Another option that is somewhat similar to the previous one is subscriber-id, defined in RFC 4580. It is, too, inserted by a relay agent that is configured to insert it. This parameter can also be specified as rfc4580, which is an alias for subscriber-id. This method is currently not implemented. * docsis-cmts - Yet another possible source of MAC address information are the DOCSIS options inserted by a CMTS that acts as a DHCPv6 relay agent in cable networks. This method attempts to extract MAC address information from suboption 1026 (cm mac) of the vendor specific option with vendor-id=4491. This vendor option is extracted from the relay-forward message, not the original client's message. * docsis-modem - Yet another possible source of MAC address information are the DOCSIS options inserted by the cable modem itself. This method attempts to extract MAC address information from suboption 36 (device id) of the vendor specific option with vendor-id=4491. This vendor option is extracted from the original client's message, not from any relay options. 8.10. Duplicate Addresses (DECLINE Support) The DHCPv6 server is configured with a certain pool of addresses that it is expected to hand out to the DHCPv6 clients. It is assumed that the server is authoritative and has complete jurisdiction over those addresses. However, due to various reasons, such as misconfiguration or a faulty client implementation that retains its address beyond the valid lifetime, there may be devices connected that use those addresses without the server's approval or knowledge. Such an unwelcome event can be detected by legitimate clients (using Duplicate Address Detection) and reported to the DHCPv6 server using a DECLINE message. The server will do a sanity check (if the client declining an address really was supposed to use it), then will conduct a clean up operation and confirm it by sending back a REPLY message. Any DNS entries related to that address will be removed, the fact will be logged and hooks will be triggered. After that is done, the address will be marked as declined (which indicates that it is used by an unknown entity and thus not available for assignment to anyone) and a probation time will be set on it. Unless otherwise configured, the probation period lasts 24 hours. After that period, the server will recover the lease (i.e. put it back into the available state) and the address will be available for assignment again. It should be noted that if the underlying issue of a misconfigured device is not resolved, the duplicate address scenario will repeat. On the other hand, it provides an opportunity to recover from such an event automatically, without any sysadmin intervention. To configure the decline probation period to a value other than the default, the following syntax can be used: "Dhcp6": { "decline-probation-period": 3600, "subnet6": [ ... ], ... } The parameter is expressed in seconds, so the example above will instruct the server to recycle declined leases after an hour. There are several statistics and hook points associated with the Decline handling procedure. The lease6_decline hook is triggered after the incoming Decline message has been sanitized and the server is about to decline the lease. The declined-addresses statistic is increased after the hook returns (both global and subnet specific variants). (See Section 7.7, "Statistics in the DHCPv4 Server" and Chapter 13, Hooks Libraries for more details on DHCPv4 statistics and Kea hook points.) Once the probation time elapses, the declined lease is recovered using the standard expired lease reclamation procedure, with several additional steps. In particular, both declined-addresses statistics (global and subnet specific) are decreased. At the same time, reclaimed-declined-addresses statistics (again in two variants, global and subnet specific) are increased. Note about statistics: The server does not decrease the assigned-addresses statistics when a DECLINE message is received and processed successfully. While technically a declined address is no longer assigned, the primary usage of the assigned-addresses statistic is to monitor pool utilization. Most people would forget to include declined-addresses in the calculation, and simply do assigned-addresses/total-addresses. This would have a bias towards under-representing pool utilization. As this has a potential for major issues, we decided not to decrease assigned addresses immediately after receiving Decline, but to do it later when we recover the address back to the available pool. 8.11. Statistics in the DHCPv6 Server Note This section describes DHCPv6-specific statistics. For a general overview and usage of statistics, see Chapter 14, Statistics. The DHCPv6 server supports the following statistics: Table 8.4. DHCPv6 Statistics +----------------------------------------------------------------------------+ | Statistic |Data Type|Description | |---------------------------------------+---------+--------------------------| | | |Number of DHCPv6 packets | | | |received. This includes | | pkt6-received | integer |all packets: valid, bogus,| | | |corrupted, rejected etc. | | | |This statistic is expected| | | |to grow rapidly. | |---------------------------------------+---------+--------------------------| | | |Number of incoming packets| | | |that were dropped. The | | | |exact reason for dropping | | | |packets is logged, but the| | | |most common reasons may | | | |be: an unacceptable or not| | pkt6-receive-drop | integer |supported packet type, | | | |direct responses are | | | |forbidden, the server-id | | | |sent by the client does | | | |not match the server's | | | |server-id or the packet is| | | |malformed. | |---------------------------------------+---------+--------------------------| | | |Number of incoming packets| | | |that could not be parsed. | | | |A non-zero value of this | | | |statistic indicates that | | | |the server received a | | pkt6-parse-failed | integer |malformed or truncated | | | |packet. This may indicate | | | |problems in your network, | | | |faulty clients, faulty | | | |relay agents or a bug in | | | |the server. | |---------------------------------------+---------+--------------------------| | | |Number of SOLICIT packets | | | |received. This statistic | | | |is expected to grow. Its | | | |increase means that | | pkt6-solicit-received | integer |clients that just booted | | | |started their | | | |configuration process and | | | |their initial packets | | | |reached your server. | |---------------------------------------+---------+--------------------------| | | |Number of ADVERTISE | | | |packets received. | | | |Advertise packets are sent| | | |by the server and the | | | |server is never expected | | | |to receive them. A | | | |non-zero value of this | | pkt6-advertise-received | integer |statistic indicates an | | | |error occurring in the | | | |network. One likely cause | | | |would be a misbehaving | | | |relay agent that | | | |incorrectly forwards | | | |ADVERTISE messages towards| | | |the server rather back to | | | |the clients. | |---------------------------------------+---------+--------------------------| | | |Number of REQUEST packets | | | |received. This statistic | | | |is expected to grow. Its | | | |increase means that | | pkt6-request-received | integer |clients that just booted | | | |received the server's | | | |response (ADVERTISE), | | | |accepted it and are now | | | |requesting an address | | | |(REQUEST). | |---------------------------------------+---------+--------------------------| | | |Number of REPLY packets | | | |received. This statistic | | | |is expected to remain zero| | | |at all times, as REPLY | | | |packets are sent by the | | | |server and the server is | | | |never expected to receive | | pkt6-reply-received | integer |them. A non-zero value | | | |indicates an error. One | | | |likely cause would be a | | | |misbehaving relay agent | | | |that incorrectly forwards | | | |REPLY messages towards the| | | |server, rather back to the| | | |clients. | |---------------------------------------+---------+--------------------------| | | |Number of RENEW packets | | | |received. This statistic | | | |is expected to grow. Its | | pkt6-renew-received | integer |increase means that | | | |clients received their | | | |addresses and prefixes and| | | |are trying to renew them. | |---------------------------------------+---------+--------------------------| | | |Number of REBIND packets | | | |received. A non-zero value| | | |indicates that clients | | | |didn't receive responses | | | |to their RENEW messages | | | |(regular lease renewal | | pkt6-rebind-received | integer |mechanism) and are | | | |attempting to find any | | | |server that is able to | | | |take over their leases. It| | | |may mean that some | | | |server's REPLY messages | | | |never reached the clients.| |---------------------------------------+---------+--------------------------| | | |Number of RELEASE packets | | | |received. This statistic | | | |is expected to grow when a| | | |device is being shut down | | | |in the network. It | | | |indicates that the address| | | |or prefix assigned is | | pkt6-release-received | integer |reported as no longer | | | |needed. Note that many | | | |devices, especially | | | |wireless, do not send | | | |RELEASE packets either | | | |because of design choice | | | |or due to the client | | | |moving out of range. | |---------------------------------------+---------+--------------------------| | | |Number of DECLINE packets | | | |received. This statistic | | | |is expected to remain | | | |close to zero. Its | | | |increase means that a | | | |client leased an address, | | | |but discovered that the | | pkt6-decline-received | integer |address is currently used | | | |by an unknown device in | | | |your network. If this | | | |statistic is growing, it | | | |may indicate a | | | |misconfigured server or | | | |devices that have | | | |statically assigned | | | |conflicting addresses. | |---------------------------------------+---------+--------------------------| | | |Number of | | | |INFORMATION-REQUEST | | | |packets received. This | | | |statistic is expected to | | | |grow if there are devices | | | |that are using stateless | | pkt6-infrequest-received | integer |DHCPv6. | | | |INFORMATION-REQUEST | | | |messages are used by | | | |clients that request | | | |stateless configuration, | | | |i.e. options and | | | |parameters other than | | | |addresses or prefixes. | |---------------------------------------+---------+--------------------------| | | |Number of DHCPv4-QUERY | | | |packets received. This | | | |statistic is expected to | | | |grow if there are devices | | | |that are using | | pkt6-dhcpv4-query-received | integer |DHCPv4-over-DHCPv6. | | | |DHCPv4-QUERY messages are | | | |used by DHCPv4 clients on | | | |an IPv6 only line which | | | |encapsulatesi the requests| | | |over DHCPv6. | |---------------------------------------+---------+--------------------------| | | |Number of DHCPv4-RESPONSE | | | |packets received. This | | | |statistic is expected to | | | |remain zero at all times, | | | |as DHCPv4-RESPONSE packets| | | |are sent by the server and| | | |the server is never | | pkt6-dhcpv4-response-received | integer |expected to receive them. | | | |A non-zero value indicates| | | |an error. One likely cause| | | |would be a misbehaving | | | |relay agent that | | | |incorrectly forwards | | | |DHCPv4-RESPONSE message | | | |towards the server rather | | | |back to the clients. | |---------------------------------------+---------+--------------------------| | | |Number of packets received| | | |of an unknown type. A | | | |non-zero value of this | | | |statistic indicates that | | pkt6-unknown-received | integer |the server received a | | | |packet that it wasn't able| | | |to recognize: either it | | | |had an unsupported type or| | | |was possibly malformed. | |---------------------------------------+---------+--------------------------| | | |Number of DHCPv6 packets | | | |sent. This statistic is | | | |expected to grow every | | | |time the server transmits | | | |a packet. In general, it | | | |should roughly match | | | |pkt6-received, as most | | pkt6-sent | integer |incoming packets cause the| | | |server to respond. There | | | |are exceptions (e.g. | | | |server receiving a REQUEST| | | |with server-id matching | | | |other server), so do not | | | |worry, if it is lesser | | | |than pkt6-received. | |---------------------------------------+---------+--------------------------| | | |Number of ADVERTISE | | | |packets sent. This | | | |statistic is expected to | | | |grow in most cases after a| | | |SOLICIT is processed. | | pkt6-advertise-sent | integer |There are certain | | | |uncommon, but valid cases | | | |where incoming SOLICIT is | | | |dropped, but in general | | | |this statistic is expected| | | |to be close to | | | |pkt6-solicit-received. | |---------------------------------------+---------+--------------------------| | | |Number of REPLY packets | | | |sent. This statistic is | | | |expected to grow in most | | | |cases after a SOLICIT | | | |(with rapid-commit), | | pkt6-reply-sent | integer |REQUEST, RENEW, REBIND, | | | |RELEASE, DECLINE or | | | |INFORMATION-REQUEST is | | | |processed. There are | | | |certain cases where there | | | |is no response. | |---------------------------------------+---------+--------------------------| | | |Number of DHCPv4-RESPONSE | | | |packets sent. This | | | |statistic is expected to | | pkt6-dhcpv4-response-sent | integer |grow in most cases after a| | | |DHCPv4-QUERY is processed.| | | |There are certain cases | | | |where there is no | | | |response. | |---------------------------------------+---------+--------------------------| | | |This statistic shows the | | | |total number of NA | | | |addresses available for | | | |DHCPv6 management for a | | | |given subnet. In other | | | |words, this is the sum of | | | |all addresses in all | | | |configured pools. This | | | |statistic changes only | | | |during configuration | | subnet[id].total-nas | integer |changes. Note that it does| | | |not take into account any | | | |addresses that may be | | | |reserved due to host | | | |reservation. The id is the| | | |subnet-id of a given | | | |subnet. This statistic is | | | |exposed for each subnet | | | |separately and is reset | | | |during a reconfiguration | | | |event. | |---------------------------------------+---------+--------------------------| | | |This statistic shows the | | | |number of NA addresses in | | | |a given subnet that are | | | |assigned. This statistic | | | |increases every time a new| | | |lease is allocated (as a | | | |result of receiving a | | | |REQUEST message) and is | | subnet[id].assigned-nas | integer |decreased every time a | | | |lease is released (a | | | |RELEASE message is | | | |received) or expires. The | | | |id is the subnet-id of a | | | |given subnet. This | | | |statistic is exposed for | | | |each subnet separately and| | | |is reset during a | | | |reconfiguration event. | |---------------------------------------+---------+--------------------------| | | |This statistic shows the | | | |total number of PD | | | |prefixes available for | | | |DHCPv6 management for a | | | |given subnet. In other | | | |words, this is the sum of | | | |all prefixes in all | | | |configured pools. This | | | |statistic changes only | | | |during configuration | | subnet[id].total-pds | integer |changes. Note it does not | | | |take into account any | | | |prefixes that may be | | | |reserved due to host | | | |reservation. The id is the| | | |subnet-id of a given | | | |subnet. This statistic is | | | |exposed for each subnet | | | |separately and is reset | | | |during a reconfiguration | | | |event. | |---------------------------------------+---------+--------------------------| | | |This statistic shows the | | | |number of PD prefixes in a| | | |given subnet that are | | | |assigned. This statistic | | | |increases every time a new| | | |lease is allocated (as a | | | |result of receiving a | | | |REQUEST message) and is | | subnet[id].assigned-pds | integer |decreased every time a | | | |lease is released (a | | | |RELEASE message is | | | |received) or expires. The | | | |id is the subnet-id of a | | | |given subnet. This | | | |statistic is exposed for | | | |each subnet separately and| | | |is reset during a | | | |reconfiguration event. | |---------------------------------------+---------+--------------------------| | | |This statistic shows the | | | |number of IPv6 addresses | | | |that are currently | | | |declined and so counts the| | | |number of leases currently| | | |unavailable. Once a lease | | | |is recovered, this | | | |statistic will be | | | |decreased. Ideally, this | | declined-addresses | integer |statistic should be zero. | | | |If this statistic is | | | |non-zero (or worse, | | | |increasing), the network | | | |administrator should | | | |investigate if there is a | | | |misbehaving device in the | | | |network. This is a global | | | |statistic that covers all | | | |subnets. | |---------------------------------------+---------+--------------------------| | | |This statistic shows the | | | |number of IPv6 addresses | | | |that are currently | | | |declined in a given | | | |subnet. This statistic | | | |counts the number of | | | |leases currently | | | |unavailable. Once a lease | | | |is recovered, this | | | |statistic will be | | | |decreased. Ideally, this | | subnet[id].declined-addresses | integer |statistic should be zero. | | | |If this statistic is | | | |non-zero (or worse, | | | |increasing), a network | | | |administrator should | | | |investigate if there is a | | | |misbehaving device in the | | | |network. The id is the | | | |subnet-id of a given | | | |subnet. This statistic is | | | |exposed for each subnet | | | |separately. | |---------------------------------------+---------+--------------------------| | | |This statistic shows the | | | |number of IPv6 addresses | | | |that were declined, but | | | |have now been recovered. | | | |Unlike declined-addresses,| | | |this statistic never | | reclaimed-declined-addresses | integer |decreases. It can be used | | | |as a long term indicator | | | |of how many actual valid | | | |Declines were processed | | | |and recovered from. This | | | |is a global statistic that| | | |covers all subnets. | |---------------------------------------+---------+--------------------------| | | |This statistic shows the | | | |number of IPv6 addresses | | | |that were declined, but | | | |have now been recovered. | | | |Unlike declined-addresses,| | | |this statistic never | | | |decreases. It can be used | |subnet[id].reclaimed-declined-addresses| integer |as a long term indicator | | | |of how many actual valid | | | |Declines were processed | | | |and recovered from. The id| | | |is the subnet-id of a | | | |given subnet. This | | | |statistic is exposed for | | | |each subnet separately. | +----------------------------------------------------------------------------+ 8.12. Management API for the DHCPv6 Server The management API allows the issuing of specific management commands, such as statistics retrieval, reconfiguration or shutdown. For more details, see Chapter 15, Management API. Currently the only supported communication channel type is UNIX stream socket. By default there are no sockets open. To instruct Kea to open a socket, the following entry in the configuration file can be used: "Dhcp6": { "control-socket": { "socket-type": "unix", "socket-name": "/path/to/the/unix/socket" }, "subnet6": [ ... ], ... } The length of the path specified by the socket-name parameter is restricted by the maximum length for the unix socket name on your operating system, i.e. the size of the sun_path field in the sockaddr_un structure, decreased by 1. This value varies on different operating systems between 91 and 107 characters. Typical values are 107 on Linux and 103 on FreeBSD. Communication over control channel is conducted using JSON structures. See the Control Channel section in the Kea Developer's Guide for more details. The DHCPv6 server supports statistic-get, statistic-reset, statistic-remove, statistic-get-all, statistic-reset-all and statistic-remove-all, specified in Section 14.3, "Commands for Manipulating Statistics". It also supports list-commands and shutdown, specified in Section 15.3.2, "list-commands" and Section 15.3.3, "shutdown", respectively. 8.13. Supported DHCPv6 Standards The following standards are currently supported: * Dynamic Host Configuration Protocol for IPv6, RFC 3315: Supported messages are SOLICIT, ADVERTISE, REQUEST, RELEASE, RENEW, REBIND, INFORMATION-REQUEST, CONFIRM and REPLY. * IPv6 Prefix Options for Dynamic Host Configuration Protocol (DHCP) version 6, RFC 3633: Supported options are IA_PD and IA_PREFIX. Also supported is the status code NoPrefixAvail. * DNS Configuration options for Dynamic Host Configuration Protocol for IPv6 (DHCPv6), RFC 3646: Supported option is DNS_SERVERS. * The Dynamic Host Configuration Protocol for IPv6 (DHCPv6) Relay Agent Remote-ID Option, RFC 4649: REMOTE-ID option is supported. * The Dynamic Host Configuration Protocol for IPv6 (DHCPv6) Client Fully Qualified Domain Name (FQDN) Option, RFC 4704: Supported option is CLIENT_FQDN. * Relay-Supplied DHCP Options, RFC 6422: Full functionality is supported: OPTION_RSOO, ability of the server to echo back the options, checks whether an option is RSOO-enabled, ability to mark additional options as RSOO-enabled. * Client Link-Layer Address Option in DHCPv6, RFC 6939: Supported option is client link-layer address option. * Issues and Recommendations with Multiple Stateful DHCPv6 Options, RFC 7550: All recommendations related to the DHCPv6 server operation are supported. 8.14. DHCPv6 Server Limitations These are the current limitations of the DHCPv6 server software. Most of them are reflections of the early stage of development and should be treated as "not implemented yet", rather than actual limitations. * The server will allocate, renew or rebind a maximum of one lease for a particular IA option (IA_NA or IA_PD) sent by a client. RFC 3315 and RFC 3633 allow for multiple addresses or prefixes to be allocated for a single IA. * Temporary addresses are not supported. * Client reconfiguration (RECONFIGURE) is not yet supported. Chapter 9. Lease Expiration in DHCPv4 and DHCPv6 Table of Contents 9.1. Lease Reclamation 9.2. Configuring Lease Reclamation 9.3. Configuring Lease Affinity 9.4. Default Configuration Values for Leases Reclamation 9.5. Reclaiming Expired Leases with Command The primary role of the DHCP server is to assign addresses and/or delegate prefixes to DHCP clients. These addresses and prefixes are often referred to as "leases". Leases are typically assigned to clients for a finite amount of time, known as the "valid lifetime". DHCP clients who wish to continue using their assigned leases, will periodically renew them by sending the appropriate message to the DHCP server. The DHCP server records the time when these leases are renewed and calculates new expiration times for them. If the client does not renew a lease before its valid lifetime elapses, the lease is considered expired. There are many situations when the client may cease lease renewals. A common scenario is when the machine running the client shuts down for an extended period of time. The process through which the DHCP server makes expired leases available for reassignment is referred to as "lease reclamation" and expired leases returned to availability through this process are referred to as "reclaimed". The DHCP server attempts to reclaim an expired lease as soon as it detects that it has expired. One way in which the server detects expiration occurs when it is trying to allocate a lease to a client and finds this lease already present in the database but expired. Another way is by periodically querying the lease database for them. Regardless of how an expired lease is detected, before it may assigned to a client, it must be reclaimed. This chapter explains how to configure the server to periodically query for the expired leases and how to minimize the impact of the periodic lease reclamation process on the server's responsiveness. Finally, it explains "lease affinity", which provides the means to assign the same lease to a returning client after its lease has expired. Although, all configuration examples in this section are provided for the DHCPv4 server, the same parameters may be used for the DHCPv6 server configuration. 9.1. Lease Reclamation Lease reclamation is the process through which an expired lease becomes available for assignment to the same or different client. This process involves the following steps for each reclaimed lease: * Invoke callouts for the lease4_expire or lease6_expire hook points if hook libraries supporting those callouts are currently loaded. * Update DNS, i.e. remove any DNS entries associated with the expired lease. * Update lease information in the lease database to indicate that the lease is now available for re-assignment. * Update counters on the server, which includes increasing the number of reclaimed leases and decreasing the number of assigned addresses or delegated prefixes. Please refer to Chapter 10, The DHCP-DDNS Server to see how to configure DNS updates in Kea, and to Chapter 13, Hooks Libraries for information about using hooks libraries. 9.2. Configuring Lease Reclamation Kea can be configured to periodically detect and reclaim expired leases. During this process the lease entries in the database are modified or removed. While this is happening the server will not process incoming DHCP messages to avoid issues with concurrent access to database information. As a result, the server will be unresponsive while lease reclamation is performed and DHCP queries will accumulate; responses will be sent once the leases reclamation cycle is complete. In deployments where response time is critical, administrators may wish to minimize the interruptions in service caused by lease reclamation. Toward this end, Kea provides configuration parameters to control: the frequency of lease reclamation cycles, the maximum number of leases processed in a single reclamation cycle, and the maximum amount of time a single reclamation cycle is allowed to run before being interrupted. The following examples demonstrate how these parameters can be used: "Dhcp4": { ... "expired-leases-processing": { "reclaim-timer-wait-time": 5, "max-reclaim-leases": 0, "max-reclaim-time": 0, "flush-reclaimed-timer-wait-time": 0, }, ... } The first parameter is expressed in seconds and specifies an interval between the two consecutive lease reclamation cycles. This is explained by the following diagram. | c1 | | c2 | |c3| | c4 | |<---->|<---------->|<-->|<---------->|<>|<---------->|<-->| ----------------------------------------------------------------> | | 5s | | 5s | | 5s | | time This diagram shows four lease reclamation cycles (c1 through c4) of variable duration. Note that the duration of the reclamation cycle depends on the number of expired leases detected and processed in the particular cycle. This duration is also usually significantly shorter than the interval between the cycles. According to the reclaim-timer-wait-time the server keeps fixed intervals of five seconds between the end of one cycle and the start of the next cycle. This guarantees the presence of 5s long periods during which the server remains responsive to DHCP queries and does not perform lease reclamation. The max-reclaim-leases and max-reclaim-time are set to 0, which sets no restriction on the maximum number of leases reclaimed in the particular cycle, or on the maximum duration of each cycle. In deployments with high lease pool utilization, relatively short valid lifetimes, and frequently disconnecting clients which allow leases to expire, the number of expired leases requiring reclamation at any given time may rise significantly. In this case it is often desirable to apply restrictions on the maximum duration of a reclamation cycle or the maximum number of leases reclaimed in a cycle. The following configuration demonstrates how this can be done: "Dhcp4": { ... "expired-leases-processing": { "reclaim-timer-wait-time": 3, "max-reclaim-leases": 100, "max-reclaim-time": 50, "unwarned-reclaim-cycles": 10, }, ... } The max-reclaim-leases parameter limits the number of leases reclaimed in a single cycle to 100. The max-reclaim-time limits the maximum duration of each cycle to 50ms. The lease reclamation cycle will be interrupted if either of these limitations is reached. The reclamation of all unreclaimed leases will be attempted in subsequent cycles. The following diagram illustrates the behavior of the system in the presence of many expired leases, when the limits are applied for the reclamation cycles. | c1 | | c2 | | c3 | | c4 | |<-->|<-------------->|<-->|<-------------->|<-->|<-------------->|<-->|<-- ------------------------------------------------------------------------------> |50ms| 3s |50ms| 3s |50ms| 3s |50ms| time The diagram demonstrates the case when each reclamation cycle would take more than 50ms, and thus is interrupted according to the value of the max-reclaim-time. This results in equal durations of all reclamation cycles over time. Note that in this example the limitation of maximum 100 leases is not reached. This may be the case when database transactions are slow or callouts in the hook libraries attached to the server are slow. Regardless, the choosing values for either the maximum number of leases or a maximum cycle time strongly depends on the particular deployment, lease database backend being used, and any hooks libraries etc. Administrators may need to experiment to tune the system to suit the dynamics of their deployment. It is important to realize that with the use of these limits, there is a risk that expired leases will accumulate faster than the server can reclaim them. This should not be the problem if the server is dealing with a temporary burst of expirations, because it should be able to eventually deal with them over time. However, if leases expire at a high rate for a longer period of time, the unreclaimed leases will pile up in the database. In order to notify the administrator that the current configuration does not satisfy the needs for reclamation of expired leases, the server issues a warning message in the log if it was unable to reclaim all leases within the last couple of reclamation cycles. The number of cycles after which such warning is issued is specified with the unwarned-reclaim-cycles configuration parameter. Setting the reclaim-timer-wait-time to 0 disables periodic reclamation of the expired leases. 9.3. Configuring Lease Affinity Suppose that a laptop goes to a sleep mode after a period of user inactivity. While the laptop is in sleep mode, its DHCP client will not renew leases obtained from the server and these leases will eventually expire. When the laptop wakes up, it is often desirable for it to continue using its previous assigned IP addresses. In order to facilitate this, the server needs to correlate returning clients with their expired leases When the client returns, the server will first check for those leases and re-assign them if they have not been assigned to another client. The ability of the server to re-assign the same lease to a returning client is referred to as "lease affinity". When lease affinity is enabled, the server will still reclaim leases according to the parameters described in Section 9.2, "Configuring Lease Reclamation", but the reclaimed leases will be held in the database (rather than removed) for the specified amount of time. When the client returns, the server will first check if there are any reclaimed leases associated with this client and re-assign them if possible. However, it is important to note that any reclaimed lease may be assigned to another client if that client specifically asks for it. Therefore, the lease affinity does not guarantee that the reclaimed lease will be available for the client who used it before; it merely increases the chances for the client to be assigned the same lease. If the lease pool is small (this mostly applies to DHCPv4 for which address space is small), there is an increased likelihood that the expired lease will be assigned to another client. Consider the following configuration: "Dhcp4": { ... "expired-leases-processing": { "reclaim-timer-wait-time": 3, "hold-reclaimed-time": 1800, "flush-reclaimed-timer-wait-time": 5 }, ... } The hold-reclaim-time specifies how many seconds after an expiration a reclaimed lease should be held in the database for re-assignment to the same client. In the example given above, reclaimed leases will be held for 30 minutes (1800s) after their expiration. During this time, the server will likely be able to re-assign the same lease to the returning client, unless another client requests this lease and the server assigns it. The server must periodically remove reclaimed leases for which the time indicated by hold-reclaim-time has elapsed. The flush-reclaimed-timer-wait-time controls how often the server removes such leases. In the example provided above, the server will initiate removal of such leases 5 seconds after the previous removal attempt was completed. Setting this value to 0 disables lease affinity, in which case leases will be removed from the lease database when they are reclaimed. If lease affinity is enabled, it is recommended that hold-reclaim-time be set to a value significantly higher than the reclaim-timer-wait-time, as timely removal of expired-reclaimed leases is less critical while the removal process may impact server responsiveness. 9.4. Default Configuration Values for Leases Reclamation The following list presents all configuration parameters pertaining to processing expired leases with their default values: * reclaim-timer-wait-time = 10 [seconds] * flush-reclaimed-timer-wait-time = 25 [seconds] * hold-reclaimed-time = 3600 [seconds] * max-reclaim-leases = 100 * max-reclaim-time = 250 [milliseconds] * unwarned-reclaim-cycles = 5 The default value for any parameter is used when this parameter not explicitly specified in the configuration. Also, the expired-leases-processing map may be omitted entirely in the configuration, in which case the default values are used for all parameters listed above. 9.5. Reclaiming Expired Leases with Command The leases-reclaim command can be used to trigger leases reclamation at any time. Please consult the Section 15.3.1, "leases-reclaim" for the details about using this command. Chapter 10. The DHCP-DDNS Server Table of Contents 10.1. Starting and Stopping the DHCP-DDNS Server 10.2. Configuring the DHCP-DDNS Server 10.2.1. Global Server Parameters 10.2.2. TSIG Key List 10.2.3. Forward DDNS 10.2.4. Reverse DDNS 10.2.5. Example DHCP-DDNS Server Configuration 10.3. DHCP-DDNS Server Limitations The DHCP-DDNS Server (kea-dhcp-ddns, known informally as D2) conducts the client side of the DDNS protocol (defined in RFC 2136) on behalf of the DHCPv4 and DHCPv6 servers (kea-dhcp4 and kea-dhcp6 respectively). The DHCP servers construct DDNS update requests, known as NameChangeRequests (NCRs), based upon DHCP lease change events and then post these to D2. D2 attempts to match each such request to the appropriate DNS server(s) and carry out the necessary conversation with those servers to update the DNS data. In order to match a request to the appropriate DNS servers, D2 must have a catalog of servers from which to select. In fact, D2 has two such catalogs, one for forward DNS and one for reverse DNS; these catalogs are referred to as DDNS Domain Lists. Each list consists of one or more named DDNS Domains. Further, each DDNS Domain has a list of one or more DNS servers that publish the DNS data for that domain. When conducting forward domain matching, D2 will compare the FQDN in the request against the name of each forward DDNS Domain. The domain whose name matches the longest portion of the FQDN is considered the best match. For example, if the FQDN is "myhost.sample.example.com.", and there are two forward domains in the catalog: "sample.example.com." and "example.com.", the former is regarded as the best match. In some cases, it may not be possible to find a suitable match. Given the same two forward domains there would be no match for the FQDN, "bogus.net", so the request would be rejected. Finally, if there are no forward DDNS Domains defined, D2 will simply disregard the forward update portion of requests. When conducting reverse domain matching, D2 constructs a reverse FQDN from the lease address in the request and compare that against the name of each reverse DDNS Domain. Again, the domain whose name matches the longest portion of the FQDN is considered the best match. For instance, if the lease address is "172.16.1.40" and there are two reverse domains in the catalog: "1.16.172.in-addr.arpa." and "16.172.in-addr.arpa", the former is the best match. As with forward matching, it is possible to not find a suitable match. Given the same two domains, there would be no match for the lease address, "192.168.1.50", and the request would be rejected. Finally, if there are no reverse DDNS Domains defined, D2 will simply disregard the reverse update portion of requests. 10.1. Starting and Stopping the DHCP-DDNS Server kea-dhcp-ddns is the Kea DHCP-DDNS server and, due to the nature of DDNS, it is run alongside either the DHCPv4 or DHCPv6 components (or both). Like other parts of Kea, it is a separate binary that can be run on its own or through keactrl (see Chapter 6, Managing Kea with keactrl). In normal operation, controlling kea-dhcp-ddns with keactrl is recommended. However, it is also possible to run the DHCP-DDNS server directly. It accepts the following command-line switches: * -c file - specifies the configuration file. This is the only mandatory switch. * -d - specifies whether the server logging should be switched to debug/verbose mode. In verbose mode, the logging severity and debuglevel specified in the configuration file are ignored and "debug" severity and the maximum debuglevel (99) are assumed. The flag is convenient, for temporarily switching the server into maximum verbosity, e.g. when debugging. * -v - prints out Kea version and exits. * -W - prints out the Kea configuration report and exits. The report is a copy of the config.report file produced by ./configure: it is embedded in the executable binary. * -W - prints out Kea configuration report and exits. The config.report may also be accessed more directly. The following command may be used to extract this information. The binary path may be found in the install directory or in the .libs subdirectory in the source tree. For example kea/src/bin/d2/.libs/kea-dhcp-ddns. strings path/kea-dhcp-ddns | sed -n 's/;;;; //p' Upon start up the module will load its configuration and begin listening for NCRs based on that configuration. During startup the server will attempt to create a PID file of the form: [localstatedir]/[conf name].kea-dhcp-ddns.pid where: * localstatedir: The value as passed into the build configure script. It defaults to "/usr/local/var". Note that this value may be overridden at run time by setting the environment variable KEA_PIDFILE_DIR. This is intended primarily for testing purposes. * conf name: The configuration file name used to start the server, minus all preceding path and file extension. For example, given a pathname of "/usr/local/etc/kea/myconf.txt", the portion used would be "myconf". If the file already exists and contains the PID of a live process, the server will issue a DHCP_DDNS_ALREADY_RUNNING log message and exit. It is possible, though unlikely, that the file is a remnant of a system crash and the process to which the PID belongs is unrelated to Kea. In such a case it would be necessary to manually delete the PID file. 10.2. Configuring the DHCP-DDNS Server Before starting kea-dhcp-ddns module for the first time, a configuration file needs to be created. The following default configuration is a template that can be customised to your requirements. "DhcpDdns": { "ip-address": "127.0.0.1", "port": 53001, "dns-server-timeout": 100, "ncr-protocol": "UDP", "ncr-format": "JSON", "tsig-keys": [ ], "forward-ddns": { "ddns-domains": [ ] }, "reverse-ddns": { "ddns-domains": [ ] } } The configuration can be divided as follows, each of which is described in its own section: * Global Server Parameters - values which control connectivity and global server behavior * TSIG Key Info - defines the TSIG keys used for secure traffic with DNS servers * Forward DDNS - defines the catalog of Forward DDNS Domains * Reverse DDNS - defines the catalog of Forward DDNS Domains 10.2.1. Global Server Parameters * ip-address - IP address on which D2 listens for requests. The default is the local loopback interface at address 127.0.0.1. You may specify either an IPv4 or IPv6 address. * port - Port on which D2 listens for requests. The default value is 53001. * dns-server-timeout - The maximum amount of time in milliseconds, that D2 will wait for a response from a DNS server to a single DNS update message. * ncr-protocol - Socket protocol to use when sending requests to D2. Currently only UDP is supported. TCP may be available in a future release. * ncr-format - Packet format to use when sending requests to D2. Currently only JSON format is supported. Other formats may be available in future releases. D2 must listen for change requests on a known address and port. By default it listens at 127.0.0.1 on port 53001. The following example illustrates how to change D2's global parameters so it will listen at 192.168.1.10 port 900: "DhcpDdns": { "ip-address": "192.168.1.10", "port": 900, ... } } Warning It is possible for a malicious attacker to send bogus NameChangeRequests to the DHCP-DDNS server. Addresses other than the IPv4 or IPv6 loopback addresses (127.0.0.1 or ::1) should only be used for testing purposes, but note that local users may still communicate with the DHCP-DDNS server. A future version of Kea will implement authentication to guard against such attacks. Note If the ip-address and port are changed, it will be necessary to change the corresponding values in the DHCP servers' "dhcp-ddns" configuration section. 10.2.2. TSIG Key List A DDNS protocol exchange can be conducted with or without TSIG (defined in RFC 2845). This configuration section allows the administrator to define the set of TSIG keys that may be used in such exchanges. To use TSIG when updating entries in a DNS Domain, a key must be defined in the TSIG Key List and referenced by name in that domain's configuration entry. When D2 matches a change request to a domain, it checks whether the domain has a TSIG key associated with it. If so, D2 will use that key to sign DNS update messages sent to and verify responses received from the domain's DNS server(s). For each TSIG key required by the DNS servers that D2 will be working with there must be a corresponding TSIG key in the TSIG Key list. As one might gather from the name, the tsig-key section of the D2 configuration lists the TSIG keys. Each entry describes a TSIG key used by one or more DNS servers to authenticate requests and sign responses. Every entry in the list has three parameters: * name - a unique text label used to identify this key within the list. This value is used to specify which key (if any) should be used when updating a specific domain. So long as it is unique its content is arbitrary, although for clarity and ease of maintenance it is recommended that it match the name used on the DNS server(s). It cannot be blank. * algorithm - specifies which hashing algorithm should be used with this key. This value must specify the same algorithm used for the key on the DNS server(s). The supported algorithms are listed below: * HMAC-MD5 * HMAC-SHA1 * HMAC-SHA224 * HMAC-SHA256 * HMAC-SHA384 * HMAC-SHA512 This value is not case sensitive. * digest-bits - is used to specify the minimum truncated length in bits. The default value 0 means truncation is forbidden, non-zero values must be an integral number of octets, be greater than 80 and the half of the full length. Note in BIND9 this parameter is appended after a dash to the algorithm name. * secret - is used to specify the shared secret key code for this key. This value is case sensitive and must exactly match the value specified on the DNS server(s). It is a base64-encoded text value. As an example, suppose that a domain D2 will be updating is maintained by a BIND9 DNS server which requires dynamic updates to be secured with TSIG. Suppose further that the entry for the TSIG key in BIND9's named.conf file looks like this: : key "key.four.example.com." { algorithm hmac-sha224; secret "bZEG7Ow8OgAUPfLWV3aAUQ=="; }; : By default, the TSIG Key list is empty: "DhcpDdns": { "tsig-keys": [ ], ... } We must extend the list with a new key: "DhcpDdns": { "tsig-keys": [ { "name": "key.four.example.com.", "algorithm": "HMAC-SHA224", "secret": "bZEG7Ow8OgAUPfLWV3aAUQ==" } ], ... } These steps would be repeated for each TSIG key needed. Note that the same TSIG key can be used with more than one domain. 10.2.3. Forward DDNS The Forward DDNS section is used to configure D2's forward update behavior. Currently it contains a single parameter, the catalog of forward DDNS Domains, which is a list of structures. "DhcpDdns": { "forward-ddns": { "ddns-domains": [ ] }, ... } By default, this list is empty, which will cause the server to ignore the forward update portions of requests. 10.2.3.1. Adding Forward DDNS Domains A forward DDNS Domain maps a forward DNS zone to a set of DNS servers which maintain the forward DNS data (i.e. name to address mapping) for that zone. You will need one forward DDNS Domain for each zone you wish to service. It may very well be that some or all of your zones are maintained by the same servers. You will still need one DDNS Domain per zone. Remember that matching a request to the appropriate server(s) is done by zone and a DDNS Domain only defines a single zone. This section describes how to add Forward DDNS Domains. Repeat these steps for each Forward DDNS Domain desired. Each Forward DDNS Domain has the following parameters: * name - The fully qualified domain name (or zone) that this DDNS Domain can update. This is value used to compare against the request FQDN during forward matching. It must be unique within the catalog. * key-name - If TSIG is used with this domain's servers, this value should be the name of the key from within the TSIG Key List to use. If the value is blank (the default), TSIG will not be used in DDNS conversations with this domain's servers. * dns-servers - A list of one or more DNS servers which can conduct the server side of the DDNS protocol for this domain. The servers are used in a first to last preference. In other words, when D2 begins to process a request for this domain it will pick the first server in this list and attempt to communicate with it. If that attempt fails, it will move to next one in the list and so on until the it achieves success or the list is exhausted. To create a new forward DDNS Domain, one must add a new domain element and set its parameters: "DhcpDdns": { "forward-ddns": { "ddns-domains": [ { "name": "other.example.com.", "key-name": "", "dns-servers": [ ] } ] } } It is permissible to add a domain without any servers. If that domain should be matched to a request, however, the request will fail. In order to make the domain useful though, we must add at least one DNS server to it. 10.2.3.1.1. Adding Forward DNS Servers This section describes how to add DNS servers to a Forward DDNS Domain. Repeat them for as many servers as desired for a each domain. Forward DNS Server entries represent actual DNS servers which support the server side of the DDNS protocol. Each Forward DNS Server has the following parameters: * hostname - The resolvable host name of the DNS server. This value is not yet implemented. * ip-address - The IP address at which the server listens for DDNS requests. This may be either an IPv4 or an IPv6 address. * port - The port on which the server listens for DDNS requests. It defaults to the standard DNS service port of 53. To create a new forward DNS Server, one must add a new server element to the domain and fill in its parameters. If for example the service is running at "172.88.99.10", then set it as follows: "DhcpDdns": { "forward-ddns": { "ddns-domains": [ { "name": "other.example.com.", "key-name": "", "dns-servers": [ { "hostname": "", "ip-address": "172.88.99.10", "port": 53 } ] } ] } } Note As stated earlier, "hostname" is not yet supported so, the parameter "ip-address" must be set to the address of the DNS server. 10.2.4. Reverse DDNS The Reverse DDNS section is used to configure D2's reverse update behavior, and the concepts are the same as for the forward DDNS section. Currently it contains a single parameter, the catalog of reverse DDNS Domains, which is a list of structures. "DhcpDdns": { "reverse-ddns": { "ddns-domains": [ ] } ... } By default, this list is empty, which will cause the server to ignore the reverse update portions of requests. 10.2.4.1. Adding Reverse DDNS Domains A reverse DDNS Domain maps a reverse DNS zone to a set of DNS servers which maintain the reverse DNS data (address to name mapping) for that zone. You will need one reverse DDNS Domain for each zone you wish to service. It may very well be that some or all of your zones are maintained by the same servers; even then, you will still need one DDNS Domain entry for each zone. Remember that matching a request to the appropriate server(s) is done by zone and a DDNS Domain only defines a single zone. This section describes how to add Reverse DDNS Domains. Repeat these steps for each Reverse DDNS Domain desired. Each Reverse DDNS Domain has the following parameters: * name - The fully qualified reverse zone that this DDNS Domain can update. This is the value used during reverse matching which will compare it with a reversed version of the request's lease address. The zone name should follow the appropriate standards: for example, to to support the IPv4 subnet 172.16.1, the name should be. "1.16.172.in-addr.arpa.". Similarly, to support an IPv6 subnet of 2001:db8:1, the name should be "1.0.0.0.8.B.D.0.1.0.0.2.ip6.arpa." Whatever the name, it must be unique within the catalog. * key-name - If TSIG should be used with this domain's servers, then this value should be the name of that key from the TSIG Key List. If the value is blank (the default), TSIG will not be used in DDNS conversations with this domain's servers. Currently this value is not used as TSIG has not been implemented. * dns-servers - a list of one or more DNS servers which can conduct the server side of the DDNS protocol for this domain. Currently the servers are used in a first to last preference. In other words, when D2 begins to process a request for this domain it will pick the first server in this list and attempt to communicate with it. If that attempt fails, it will move to next one in the list and so on until the it achieves success or the list is exhausted. To create a new reverse DDNS Domain, one must add a new domain element and set its parameters. For example, to support subnet 2001:db8:1::, the following configuration could be used: "DhcpDdns": { "reverse-ddns": { "ddns-domains": [ { "name": "1.0.0.0.8.B.D.0.1.0.0.2.ip6.arpa.", "key-name": "", "dns-servers": [ ] } ] } } It is permissible to add a domain without any servers. If that domain should be matched to a request, however, the request will fail. In order to make the domain useful though, we must add at least one DNS server to it. 10.2.4.1.1. Adding Reverse DNS Servers This section describes how to add DNS servers to a Reverse DDNS Domain. Repeat them for as many servers as desired for each domain. Reverse DNS Server entries represents a actual DNS servers which support the server side of the DDNS protocol. Each Reverse DNS Server has the following parameters: * hostname - The resolvable host name of the DNS server. This value is currently ignored. * ip-address - The IP address at which the server listens for DDNS requests. * port - The port on which the server listens for DDNS requests. It defaults to the standard DNS service port of 53. To create a new reverse DNS Server, one must first add a new server element to the domain and fill in its parameters. If for example the service is running at "172.88.99.10", then set it as follows: "DhcpDdns": { "reverse-ddns": { "ddns-domains": [ { "name": "1.0.0.0.8.B.D.0.1.0.0.2.ip6.arpa.", "key-name": "", "dns-servers": [ { "hostname": "", "ip-address": "172.88.99.10", "port": 53 } ] } ] } } Note As stated earlier, "hostname" is not yet supported so, the parameter "ip-address" must be set to the address of the DNS server. 10.2.5. Example DHCP-DDNS Server Configuration This section provides an example DHCP-DDNS server configuration based on a small example network. Let's suppose our example network has three domains, each with their own subnet. Table 10.1. Our example network +------------------------------------------------------------------------+ | Domain | Subnet | Forward DNS Servers | Reverse DNS | | | | | Servers | |------------------+-----------------+---------------------+-------------| | four.example.com | 192.0.2.0/24 | 172.16.1.5, | 172.16.1.5, | | | | 172.16.2.5 | 172.16.2.5 | |------------------+-----------------+---------------------+-------------| | six.example.com | 2001:db8:1::/64 | 3001:1::50 | 3001:1::51 | |------------------+-----------------+---------------------+-------------| | example.com | 192.0.0.0/16 | 172.16.2.5 | 172.16.2.5 | +------------------------------------------------------------------------+ We need to construct three forward DDNS Domains: Table 10.2. Forward DDNS Domains Needed +-------------------------------------------------+ | # | DDNS Domain Name | DNS Servers | |----+-------------------+------------------------| | 1. | four.example.com. | 172.16.1.5, 172.16.2.5 | |----+-------------------+------------------------| | 2. | six.example.com. | 3001:1::50 | |----+-------------------+------------------------| | 3. | example.com. | 172.16.2.5 | +-------------------------------------------------+ As discussed earlier, FQDN to domain matching is based on the longest match. The FQDN, "myhost.four.example.com.", will match the first domain ("four.example.com") while "admin.example.com." will match the third domain ("example.com"). The FQDN, "other.example.net." will fail to match any domain and would be rejected. The following example configuration specified the Forward DDNS Domains. "DhcpDdns": { "forward-ddns": { "ddns-domains": [ { "name": "four.example.com.", "key-name": "", "dns-servers": [ { "ip-address": "172.16.1.5" }, { "ip-address": "172.16.2.5" } ] }, { "name": "six.example.com.", "key-name": "", "dns-servers": [ { "ip-address": "2001:db8::1" } ] }, { "name": "example.com.", "key-name": "", "dns-servers": [ { "ip-address": "172.16.2.5" } ] }, ] } } Similarly, we need to construct the three reverse DDNS Domains: Table 10.3. Reverse DDNS Domains Needed +-----------------------------------------------------------------+ | # | DDNS Domain Name | DNS Servers | |----+-----------------------------------+------------------------| | 1. | 2.0.192.in-addr.arpa. | 172.16.1.5, 172.16.2.5 | |----+-----------------------------------+------------------------| | 2. | 1.0.0.0.8.d.b.0.1.0.0.2.ip6.arpa. | 3001:1::50 | |----+-----------------------------------+------------------------| | 3. | 0.182.in-addr.arpa. | 172.16.2.5 | +-----------------------------------------------------------------+ An address of "192.0.2.150" will match the first domain, "2001:db8:1::10" will match the second domain, and "192.0.50.77" the third domain. These Reverse DDNS Domains are specified as follows: "DhcpDdns": { "reverse-ddns": { "ddns-domains": [ { "name": "2.0.192.in-addr.arpa.", "key-name": "", "dns-servers": [ { "ip-address": "172.16.1.5" }, { "ip-address": "172.16.2.5" } ] } { "name": "1.0.0.0.8.B.D.0.1.0.0.2.ip6.arpa.", "key-name": "", "dns-servers": [ { "ip-address": "2001:db8::1" } ] } { "name": "0.192.in-addr.arpa.", "key-name": "", "dns-servers": [ { "ip-address": "172.16.2.5" } ] } ] } } 10.3. DHCP-DDNS Server Limitations The following are the current limitations of the DHCP-DDNS Server. * Requests received from the DHCP servers are placed in a queue until they are processed. Currently all queued requests are lost when the server shuts down. Chapter 11. The LFC process Table of Contents 11.1. Overview 11.2. Command Line Options 11.1. Overview kea-lfc is a service process that removes redundant information from the files used to provide persistent storage for the memfile data base backend. This service is written to run as a stand alone process. While kea-lfc can be started externally, there is usually no need to do this. kea-lfc is run on a periodic basis by the Kea DHCP servers. The process operates on a set of files, using them for input and output of the lease entries and to indicate where it is in the process in case of an interruption. Currently the caller must supply names for all of the files, in the future this requirement may be relaxed with the process getting the names from either the configuration file or from defaults. 11.2. Command Line Options kea-lfc is run as follows: kea-lfc [-4 | -6] -c config-file -p pid-file -x previous-file -i copy-file -o output-file -f finish-file The argument -4 or -6 selects the protocol version of the lease files. The -c argument specifies the configuration file. This is required, but not currently used by the process. The -p argument specifies the PID file. When the kea-lfc process starts it attempts to determine if another instance of the process is already running by examining the pid file. If one is already running the new process is terminated. If one isn't running it writes its pid into the pid file. The other filenames specify where the kea-lfc process should look for input, write its output and use for bookkeeping. * previous -- When kea-lfc starts this is the result of any previous run of kea-lfc. When kea-lfc finishes it is the result of this run. If kea-lfc is interrupted before completing, this file may not exist. * input -- Before the DHCP server invokes kea-lfc it will move the current lease file here and then call kea-lfc with this file. * output -- The temporary file kea-lfc should use to write the leases. Upon completion of writing this file, it will be moved to the finish file (see below). * finish -- Another temporary file kea-lfc uses for bookkeeping. When kea-lfc completes writing the outputfile it moves it to this file name. After kea-lfc finishes deleting the other files (previous and input) it moves this file to previous lease file. By moving the files in this fashion the kea-lfc and the DHCP server processes can determine the correct file to use even if one of the processes was interrupted before completing its task. There are several additional arguments mostly for debugging purposes. -d Sets the logging level to debug. -v and -V print out version stamps with -V providing a longer form. -h prints out the usage string. Chapter 12. Client Classification Table of Contents 12.1. Client Classification Overview 12.2. Using Static Host Reservations In Classification 12.3. Using Vendor Class Information In Classification 12.4. Using Expressions In Classification 12.4.1. Logical operators 12.4.2. Substring 12.4.3. Concat 12.5. Configuring Classes 12.6. Configuring Subnets With Class Information 12.7. Using Classes 12.8. Classes and Hooks 12.9. Debugging Expressions 12.1. Client Classification Overview In certain cases it is useful to differentiate between different types of clients and treat them accordingly. Common reasons include: * The clients represent different pieces of topology, e.g. a cable modem is different to the clients behind that modem. * The clients have different behavior, e.g. a smart phone behaves differently to a laptop. * The clients require different values for some options, e.g. a docsis3.0 cable modem requires different settings to docsis2.0 cable modem. It is envisaged that client classification will be used for changing the behavior of almost any part of the DHCP message processing, including the assignment of leases from different pools, the assignment of different options (or different values of the same options) etc. In the current release of the software however, there are only three mechanisms that take advantage of client classification: subnet selection, assignment of different options and, for DHCPv4 cable modems, the setting of specific options for use with the TFTP server address and the boot file field. The process of doing classification is conducted in three steps: 1. Assess an incoming packet and assign it to zero or more classes. 2. Choose a subnet, possibly based on the class information. 3. Assign options, again possibly based on the class information. When determining which options to include in the response the server will examine the union of options from all of the assigned classes. In the case two or more classes include the same option, the value from the first class examined will be used. When choosing a subnet, the server will iterate over all of the subnets that are feasible given the information found in the packet (client address, relay address etc). It will use the first subnet it finds that either doesn't have a class associated with it or that has a class which matches one of the packet's classes. In the future the processing order of the various classes may be specified but for now it is being left unspecified and may change in future releases. As an example, imagine that an incoming packet matches two classes. Class "foo" defines values for an NTP server (option 42 in DHCPv4) and an SMTP server (option 69 in DHCPv4) while class "bar" defines values for an NTP server and a POP3 server (option 70 in DHCPv4). The server will examine the three options NTP, SMTP and POP3 and return any of them that the client requested. As the NTP server was defined twice the server will choose only one of the values for the reply: the class from which the value is obtained is unspecified. There are two methods of doing classification. The first is automatic and relies on examining the values in the vendor class options. Information from these options is extracted and a class name is constructed from it and added to the class list for the packet. The second allows you to specify an expression that is evaluated for each packet. If the result is true, the packet is a member of the class. Note Care should be taken with client classification as it is easy for clients that do not meet class criteria to be denied any service altogether. 12.2. Using Static Host Reservations In Classification Classes can be statically assigned to the clients using techniques described in Section 7.3.6, "Reserving Client Classes in DHCPv4" and Section 8.3.5, "Reserving Client Classes in DHCPv6". 12.3. Using Vendor Class Information In Classification The server checks whether an incoming DHCPv4 packet includes the vendor class identifier option (60) or an incoming DHCPv6 packet includes the vendor class option (16). If it does, the content of that option is prepended with "VENDOR_CLASS_" and the result is interpreted as a class. For example, modern cable modems will send this option with value "docsis3.0" and so the packet will belong to class "VENDOR_CLASS_docsis3.0". 12.4. Using Expressions In Classification The expression portion of classification contains operators and values. All values are currently strings and operators take a string or strings and return another string. When all the operations have completed the result should be a value of "true" or "false". The packet belongs to the class (and the class name is added to the list of classes) if the result is "true". Expressions are written in standard format and can be nested. Expressions are pre-processed during the parsing of the configuration file and converted to an internal representation. This allows certain types of errors to be caught and logged during parsing. Examples of these errors include an incorrect number or types of arguments to an operator. The evaluation code will also check for this class of error and generally throw an exception, though this should not occur in a normally functioning system. Other issues, for example the starting position of a substring being outside of the substring or an option not existing in the packet, result in the operator returning an empty string. Expressions are a work in progress and the supported operators and values are limited. The expectation is that additional operators and values will be added over time, however the basic mechanisms will remain the same. Table 12.1. List of Classification Values +---------------------------------------------------------------------------------+ | Name | Example expression | Example value | Description | |---------------+-----------------------------+----------------+------------------| |String literal |'example' |'example' |A string | |---------------+-----------------------------+----------------+------------------| |Hexadecimal |0x5a7d |'Z}' |A hexadecimal | |string literal | | |string | |---------------+-----------------------------+----------------+------------------| |IP address |10.0.0.1 |0x0a000001 |An IP address | |literal | | | | |---------------+-----------------------------+----------------+------------------| |Integer literal|123 |'123' |A 32 bit unsigned | | | | |integer value | |---------------------------------------------------------------------------------| |---------------------------------------------------------------------------------| | | | |The value of the | |Binary content |option[123].hex |'(content of the|option with given | |of the option | |option)' |code from the | | | | |packet as hex | |---------------+-----------------------------+----------------+------------------| | | | |If the option with| |Option | | |given code is | |existence |option[123].exists |'true' |present in the | | | | |packet "true" else| | | | |"false" | |---------------+-----------------------------+----------------+------------------| | | | |The value of | |DHCPv4 relay | | |sub-option with | |agent |relay4[123].hex |'(content of the|given code from | |sub-option | |RAI sub-option)'|the DHCPv4 Relay | | | | |Agent Information | | | | |option (option 82)| |---------------+-----------------------------+----------------+------------------| | | | |The value of the | | | | |option with code | |DHCPv6 Relay |relay6[nest].option[code].hex|(value of the |"code" from the | |Options | |option) |relay | | | | |encapsulation | | | | |"nest" | |---------------+-----------------------------+----------------+------------------| | | | |The value of the | |DHCPv6 Relay | | |peer address field| |Peer Address |relay6[nest].peeraddr |2001:DB8::1 |from the relay | | | | |encapsulation | | | | |"nest" | |---------------+-----------------------------+----------------+------------------| | | | |The value of the | |DHCPv6 Relay | | |link address field| |Link Address |relay6[nest].linkaddr |2001:DB8::1 |from the relay | | | | |encapsulation | | | | |"nest" | |---------------+-----------------------------+----------------+------------------| |Interface name | | |The name of the | |of packet |pkt.iface |eth0 |incoming interface| | | | |of a DHCP packet. | |---------------+-----------------------------+----------------+------------------| |Source address | | |The IP source | |of packet |pkt.src |10.1.2.3 |address of a DHCP | | | | |packet. | |---------------+-----------------------------+----------------+------------------| |Destination | | |The IP destination| |address of |pkt.dst |10.1.2.3 |address of a DHCP | |packet | | |packet. | |---------------+-----------------------------+----------------+------------------| | | | |The length of a | | | | |DHCP packet (UDP | |Length of |pkt.len |513 |header field), | |packet | | |expressed as a 32 | | | | |bit unsigned | | | | |integer. | |---------------+-----------------------------+----------------+------------------| | | | |The value of the | |Hardware | | |chaddr field of | |address in |pkt4.mac |0x010203040506 |the DHCPv4 packet,| |DHCPv4 packet | | |hlen (0 to 16) | | | | |bytes | |---------------+-----------------------------+----------------+------------------| |Hardware length| | |The value of the | |in DHCPv4 |pkt4.hlen |6 |hlen field of the | |packet | | |DHCPv4 packet | | | | |padded to 4 bytes | |---------------+-----------------------------+----------------+------------------| |Hardware type | | |The value of the | |in DHCPv4 |pkt4.htype |6 |htype field of the| |packet | | |DHCPv4 packet | | | | |padded to 4 bytes | |---------------+-----------------------------+----------------+------------------| | | | |The value of the | |ciaddr field in| | |ciaddr field of | |DHCPv4 packet |pkt4.ciaddr |192.0.2.1 |the DHCPv4 packet | | | | |(IPv4 address, 4 | | | | |bytes) | |---------------+-----------------------------+----------------+------------------| | | | |The value of the | |giaddr field in| | |giaddr field of | |DHCPv4 packet |pkt4.giaddr |192.0.2.1 |the DHCPv4 packet | | | | |(IPv4 address, 4 | | | | |bytes) | |---------------+-----------------------------+----------------+------------------| | | | |The value of the | |yiaddr field in| | |yiaddr field of | |DHCPv4 packet |pkt4.yiaddr |192.0.2.1 |the DHCPv4 packet | | | | |(IPv4 address, 4 | | | | |bytes) | |---------------+-----------------------------+----------------+------------------| | | | |The value of the | |siaddr field in| | |siaddr field of | |DHCPv4 packet |pkt4.siaddr |192.0.2.1 |the DHCPv4 packet | | | | |(IPv4 address, 4 | | | | |bytes) | |---------------+-----------------------------+----------------+------------------| | | | |The value of the | | | | |message type field| |Message Type in|pkt4.msgtype |1 |in the DHCPv4 | |DHCPv4 packet | | |packet (expressed | | | | |as a 32 bit | | | | |unsigned integer).| |---------------+-----------------------------+----------------+------------------| | | | |The value of the | |Transaction ID | | |transaction id in | |(xid) in DHCPv4|pkt4.transid |12345 |the DHCPv4 packet | |packet | | |(expressed as a 32| | | | |bit unsigned | | | | |integer). | |---------------+-----------------------------+----------------+------------------| | | | |The value of the | | | | |message type field| |Message Type in|pkt6.msgtype |1 |in the DHCPv6 | |DHCPv6 packet | | |packet (expressed | | | | |as a 32 bit | | | | |unsigned integer).| |---------------+-----------------------------+----------------+------------------| | | | |The value of the | |Transaction ID | | |transaction id in | |in DHCPv6 |pkt6.transid |12345 |the DHCPv6 packet | |packet | | |(expressed as a 32| | | | |bit unsigned | | | | |integer). | |---------------+-----------------------------+----------------+------------------| | | | |Returns whether a | |Vendor option | | |vendor option from| |existence (any |vendor[*].exists |true |any vendor is | |vendor) | | |present ('true') | | | | |or absent | | | | |('false'). | |---------------+-----------------------------+----------------+------------------| | | | |Returns whether a | | | | |vendor option from| |Vendor option | | |specified vendor | |existence |vendor[4491].exists |true |(determined by its| |(specific | | |enterprise-id) is | |vendor) | | |present ('true') | | | | |or absent | | | | |('false'). | |---------------+-----------------------------+----------------+------------------| | | | |If the vendor | | | | |option is present,| |Enterprise-id | | |it returns the | |from vendor |vendor.enterprise |4491 |value of the | |option | | |enterprise-id | | | | |field padded to 4 | | | | |bytes. Returns "" | | | | |otherwise. | |---------------+-----------------------------+----------------+------------------| | | | |Returns 'true' if | | | | |there is vendor | | | | |option with | |Vendor | | |specified | |sub-option |vendor[4491].option[1].exists|true |enterprise-id and | |existence | | |given sub-option | | | | |is present. | | | | |Returns 'false' | | | | |otherwise. | |---------------+-----------------------------+----------------+------------------| | | | |Returns content of| | | | |the specified | | | | |sub-option of a | |Vendor | | |vendor option with| |sub-option |vendor[4491].option[1].hex |docsis3.0 |specified | |content | | |enterprise id. | | | | |Returns '' if no | | | | |such option or | | | | |sub-option is | | | | |present. | |---------------+-----------------------------+----------------+------------------| | | | |Returns whether a | |Vendor class | | |vendor class | |option |vendor-class[*].exists |true |option from any | |existence (any | | |vendor is present | |vendor) | | |('true') or absent| | | | |('false'). | |---------------+-----------------------------+----------------+------------------| | | | |Returns whether a | | | | |vendor class | |Vendor class | | |option from | |option | | |specified vendor | |existence |vendor-class[4491].exists |true |(determined by its| |(specific | | |enterprise-id) is | |vendor) | | |present ('true') | | | | |or absent | | | | |('false'). | |---------------+-----------------------------+----------------+------------------| | | | |If the vendor | | | | |option is present,| |Enterprise-id | | |it returns the | |from vendor |vendor-class.enterprise |4491 |value of the | |class option | | |enterprise-id | | | | |field padded to 4 | | | | |bytes. Returns "" | | | | |otherwise. | |---------------+-----------------------------+----------------+------------------| | | | |Returns content of| | | | |the first data | |First data | | |chunk from the | |chunk from | | |vendor class | |vendor class |vendor-class[4491].data |docsis3.0 |option with | |option | | |specified | | | | |enterprise-id. | | | | |Returns "" if | | | | |missing. | |---------------+-----------------------------+----------------+------------------| | | | |Returns content of| | | | |the specified data| | | | |chunk of a vendor | |Specific data | | |class option with | |chunk from |vendor-class[4491].data[3] |docsis3.0 |specified | |vendor class | | |enterprise id. | |option | | |Returns '' if no | | | | |such option or | | | | |data chunk is | | | | |present. | +---------------------------------------------------------------------------------+ Notes: * Hexadecimal strings are converted into a string as expected. The starting "0X" or "0x" is removed and if the string is an odd number of characters a "0" is prepended to it. * IP addresses are converted into strings of length 4 or 16. IPv4, IPv6, and IPv4 embedded IPv6 (e.g., IPv4 mapped IPv6) addresses are supported. * Integers in an expression are converted to 32 bit unsigned integers and are represented as four-byte strings. For example 123 is represented as 0x0000007b. All expressions that return numeric values use 32-bit unsigned integers, even if the field in the packet is smaller. In general it is easier to use decimal notation to represent integers, but it is also possible to use hex notation. When using hex notation to represent an integer care should be taken to make sure the value is represented as 32 bits, e.g. use 0x00000001 instead of 0x1 or 0x01. Also, make sure the value is specified in network order, e.g. 1 is represented as 0x00000001. * "option[code].hex" extracts the value of the option with the code "code" from the incoming packet. If the packet doesn't contain the option, it returns the empty string. The string is presented as a byte string of the option payload without the type code or length fields. * "option[code].exists" checks if an option with the code "code" is present in the incoming packet. It can be used with empty options. * "relay4[code].hex" attempts to extract the value of the sub-option "code" from the option inserted as the DHCPv4 Relay Agent Information (82) option. If the packet doesn't contain a RAI option, or the RAI option doesn't contain the requested sub-option, the expression returns an empty string. The string is presented as a byte string of the option payload without the type code or length fields. This expression is allowed in DHCPv4 only. * "relay4" shares the same representation types as "option", for instance "relay4[code].exists" is supported. * "relay6[nest]" allows access to the encapsulations used by any DHCPv6 relays that forwarded the packet. The "nest" level specifies the relay from which to extract the information, with a value of 0 indicating the relay closest to the DHCPv6 server. If the requested encapsulation doesn't exist an empty string "" is returned. This expression is allowed in DHCPv6 only. * "relay6[nest].option[code]" shares the same representation types as "option", for instance "relay6[nest].option[code].exists" is supported. * Expressions starting with "pkt4" can be used only in DHCPv4. They allows access to DHCPv4 message fields. * "pkt6" refers to information from the client request. To access any information from an intermediate relay use "relay6". "pkt6.msgtype" and "pkt6.transid" output a 4 byte binary string for the message type or transaction id. For example the message type SOLICIT will be "0x00000001" or simply 1 as in "pkt6.msgtype == 1". * Vendor option means Vendor-Identifying Vendor-specific Information option in DHCPv4 (code 125, see Section 4 of RFC 3925) and Vendor-specific Information Option in DHCPv6 (code 17, defined in Section 22.17 of RFC 3315). Vendor class option means Vendor-Identifying Vendor Class Option in DHCPv4 (code 124, see Section 3 of RFC 3925) in DHCPv4 and Class Option in DHCPv6 (code 16, see Section 22.16 of RFC 3315). Vendor options may have sub-options that are referenced by their codes. Vendor class options do not have sub-options, but rather data chunks, which are referenced by index value. Index 0 means the first data chunk, Index 1 is for the second data chunk (if present), etc. * In the vendor and vendor-class constructs Asterisk (*) or 0 can be used to specify a wildcard enterprise-id value, i.e. it will match any enterprise-id value. * Vendor Class Identifier (option 60 in DHCPv4) can be accessed using option[60] expression. * RFC3925 and RFC3315 allow for multiple instances of vendor options to appear in a single message. The client classification code currently examines the first instance if more than one appear. For vendor.enterprise and vendor-class.enterprise expressions, the value from the first instance is returned. Please submit a feature request on Kea website if you need support for multiple instances. Table 12.2. List of Classification Expressions +------------------------------------------------------------------------+ | Name | Example | Description | |-----------+--------------------------------+---------------------------| | | | Compare the two values | | Equal | 'foo' == 'bar' | and return "true" or | | | | "false" | |-----------+--------------------------------+---------------------------| | Not | not ('foo' == 'bar') | Logical negation | |-----------+--------------------------------+---------------------------| | And | ('foo' == 'bar') and ('bar' == | Logical and | | | 'foo') | | |-----------+--------------------------------+---------------------------| | Or | ('foo' == 'bar') or ('bar' == | Logical or | | | 'foo') | | |-----------+--------------------------------+---------------------------| | Substring | substring('foobar',0,3) | Return the requested | | | | substring | |-----------+--------------------------------+---------------------------| | Concat | concat('foo','bar') | Return the concatenation | | | | of the strings | +------------------------------------------------------------------------+ 12.4.1. Logical operators The Not, And and Or logical operators are the common operators. Not has the highest precedence and Or the lowest. And and Or are (left) associative, parentheses around a logical expression can be used to enforce a specific grouping, for instance in "A and (B or C)" (without parentheses "A and B or C" means "(A and B) or C"). 12.4.2. Substring The substring operator "substring(value, start, length)" accepts both positive and negative values for the starting position and the length. For "start", a value of 0 is the first byte in the string while -1 is the last byte. If the starting point is outside of the original string an empty string is returned. "length" is the number of bytes to extract. A negative number means to count towards the beginning of the string but doesn't include the byte pointed to by "start". The special value "all" means to return all bytes from start to the end of the string. If length is longer than the remaining portion of the string then the entire remaining portion is returned. Some examples may be helpful: substring('foobar', 0, 6) == 'foobar' substring('foobar', 3, 3) == 'bar' substring('foobar', 3, all) == 'bar' substring('foobar', 1, 4) == 'ooba' substring('foobar', -5, 4) == 'ooba' substring('foobar', -1, -3) == 'oba' substring('foobar', 4, -2) == 'ob' substring('foobar', 10, 2) == '' 12.4.3. Concat The concat function "concat(string1, string2)" returns the concatenation of its two arguments. For instance: concat('foo', 'bar') == 'foobar' Note The expression for each class is executed on each packet received. If the expressions are overly complex, the time taken to execute them may impact the performance of the server. If you need complex or time consuming expressions you should write a hook to perform the necessary work. 12.5. Configuring Classes A class contains three items: a name, a test expression and option data. The name must exist and must be unique amongst all classes. The test expression and option data are optional. The test expression is a string containing the logical expression used to determine membership in the class. The entire expression is in double quotes. The option data is a list which defines any options that should be assigned to members of this class. In the following example the class named "Client_foo" is defined. It is comprised of all clients whose client ids (option 61) start with the string "foo". Members of this class will be given 192.0.2.1 and 192.0.2.2 as their domain name servers. "Dhcp4": { "client-classes": [ { "name": "Client_foo", "test": "substring(option[61].hex,0,3) == 'foo'", "option-data": [ { "name": "domain-name-servers", "code": 6, "space": "dhcp4", "csv-format": true, "data": "192.0.2.1, 192.0.2.2" } ] }, ... ], ... } This example shows a client class being defined for use by the DHCPv6 server. In it the class named "Client_enterprise" is defined. It is comprised of all clients who's client identifiers start with the given hex string (which would indicate a DUID based on an enterprise id of 0xAABBCCDD). Members of this class will be given an 2001:db8:0::1 and 2001:db8:2::1 as their domain name servers. "Dhcp6": { "client-classes": [ { "name": "Client_enterprise", "test": "substring(option[1].hex,0,6) == 0x0002AABBCCDD'", "option-data": [ { "name": "dns-servers", "code": 23, "space": "dhcp6", "csv-format": true, "data": "2001:db8:0::1, 2001:db8:2::1" } ] }, ... ], ... } 12.6. Configuring Subnets With Class Information In certain cases it beneficial to restrict access to certain subnets only to clients that belong to a given class, using the "client-class" keyword when defining the subnet. Let's assume that the server is connected to a network segment that uses the 192.0.2.0/24 prefix. The Administrator of that network has decided that addresses from range 192.0.2.10 to 192.0.2.20 are going to be managed by the DHCP4 server. Only clients belonging to client class Client_foo are allowed to use this subnet. Such a configuration can be achieved in the following way: "Dhcp4": { "client-classes": [ { "name": "Client_foo", "test": "substring(option[61].hex,0,3) == 'foo'", "option-data": [ { "name": "domain-name-servers", "code": 6, "space": "dhcp4", "csv-format": true, "data": "192.0.2.1, 192.0.2.2" } ] }, ... ], "subnet4": [ { "subnet": "192.0.2.0/24", "pools": [ { "pool": "192.0.2.10 - 192.0.2.20" } ], "client-class": "Client_foo" }, ... ],, ... } The following example shows restricting access to a DHCPv6 subnet. This configuration will restrict use of the addresses 2001:db8:1::1 to 2001:db8:1::FFFF to members of the "Client_enterprise" class. "Dhcp6": { "client-classes": [ { "name": "Client_enterprise", "test": "substring(option[1].hex,0,6) == 0x0002AABBCCDD'", "option-data": [ { "name": "dns-servers", "code": 23, "space": "dhcp6", "csv-format": true, "data": "2001:db8:0::1, 2001:db8:2::1" } ] }, ... ], "subnet6": [ { "subnet": "2001:db8:1::/64", "pools": [ { "pool": "2001:db8:1::-2001:db8:1::ffff" } ], "client-class": "Client_enterprise" } ], ... } 12.7. Using Classes Currently classes can be used for two functions. They can supply options to the members of the class and they can be used to choose a subnet from which an address will be assigned to the class member. When supplying options, options defined as part of the class definition are considered "class globals". They will override any global options that may be defined and in turn will be overridden by any options defined for an individual subnet. 12.8. Classes and Hooks You may use a hook to classify your packets. This may be useful if the expression would either be complex or time consuming and be easier or better to write as code. Once the hook has added the proper class name to the packet the rest of the classification system will work as normal in choosing a subnet and selecting options. For a description of hooks see Chapter 13, Hooks Libraries, for a description on configuring classes see Section 12.5, "Configuring Classes" and Section 12.6, "Configuring Subnets With Class Information". 12.9. Debugging Expressions While you are constructing your classification expressions you may find it useful to enable logging see Chapter 17, Logging for a more complete description of the logging facility. To enable the debug statements in the classifciaton system you will need to set the severity to "DEBUG" and the debug level to at least 55. The specific loggers are "kea-dhcp4.eval" and "kea-dhcp6.eval". In order to understand the logging statements one must understand a bit about how expressions are evaluated, for a more complete description refer to the design document at http://kea.isc.org/wiki/KeaDesigns. In brief there are two structures used during the evaluation of an expression: a list of tokens which represent the expressions and a value stack which represents the values being manipulated. The list of tokens is created when the configuration file is processed with most expressions and values being converted to a token. The list is organized in reverse Polish notation. During execution, the list will be traversed in order. As each token is executed it will be able to pop values from the top of the stack and eventually push its result on the top of the stack. Imagine the following expression: "test": "substring(option[61].hex,0,3) == 'foo'", This will result in the following tokens: option, number (0), number (3), substring, text ('foo'), equals In this example the first three tokens will simply push values onto the stack. The substring token will then remove those three values and compute a result that it places on the stack. The text option also places a value on the stack and finally the equals token removes the two tokens on the stack and places its result on the stack. When debug logging is enabled, each time a token is evaluated it will emit a log message indicating the values of any objects that were popped off of the value stack and any objects that were pushed onto the value stack. The values will be displayed as either text if the command is known to use text values or hexadecimal if the command either uses binary values or can manipulate either text or binary values. For expressions that pop multiple values off the stack, the values will be displayed in the order they were popped. For most expressions this won't matter but for the concat expression the values are displayed in reverse order from how they are written in the expression. Let us assume that the following test has been entered into the configuration. This example skips most of the configuration to concentrate on the test. "test": "substring(option[61].hex,0,3) == 'foo'", The logging might then resemble this: 2016-05-19 13:35:04.163 DEBUG [kea.eval/44478] EVAL_DEBUG_OPTION Pushing option 61 with value 0x666F6F626172 2016-05-19 13:35:04.164 DEBUG [kea.eval/44478] EVAL_DEBUG_STRING Pushing text string '0' 2016-05-19 13:35:04.165 DEBUG [kea.eval/44478] EVAL_DEBUG_STRING Pushing text string '3' 2016-05-19 13:35:04.166 DEBUG [kea.eval/44478] EVAL_DEBUG_SUBSTRING Popping length 3, start 0, string 0x666F6F626172 pushing result 0x666F6F 2016-05-19 13:35:04.167 DEBUG [kea.eval/44478] EVAL_DEBUG_STRING Pushing text string 'foo' 2016-05-19 13:35:04.168 DEBUG [kea.eval/44478] EVAL_DEBUG_EQUAL Popping 0x666F6F and 0x666F6F pushing result 'true' Note The debug logging may be quite verbose if you have a number of expressions to evaluate. It is intended as an aid in helping you create and debug your expressions. You should plan to disable debug logging when you have your expressions working correctly. You also may wish to include only one set of expressions at a time in the configuration file while debugging them in order to limit the log statements. For example when adding a new set of expressions you might find it more convenient to create a configuration file that only includes the new expressions until you have them working correctly and then add the new set to the main configuration file. Chapter 13. Hooks Libraries Table of Contents 13.1. Introduction 13.2. Configuring Hooks Libraries 13.3. Available Hooks Libraries 13.3.1. user_chk: Checking User Access 13.3.2. Forensic Logging Hooks 13.1. Introduction Although Kea offers a lot of flexibility, there may be cases where its behavior needs customisation. To accommodate this possibility, Kea includes the idea of "Hooks". This feature lets Kea load one or more dynamically-linked libraries (known as "hooks libraries") and, at various points in its processing ("hook points"), call functions in them. Those functions perform whatever custom processing is required. Hooks libraries are attached to individual Kea processes, not to Kea as a whole. This means (for example) that it is possible to associate one set of libraries with the DHCP4 server and a different set to the DHCP6 server. Another point to note is that it is possible for a process to load multiple libraries. When processing reaches a hook point, Kea calls the hooks library functions attached to it. If multiple libraries have attached a function to a given hook point, Kea calls all of them, in the order in which the libraries are specified in the configuration file. The order may be important: consult the documentation of the libraries to see if this is the case. The next section describes how to configure hooks libraries. If you are interested in writing your own hooks library, information can be found in the Kea Developer's Guide. 13.2. Configuring Hooks Libraries The hooks libraries for a given process are configured using the hooks-libraries keyword in the configuration for that process. (Note that the word "hooks" is plural). The value of the keyword is an array of map structures, each structure corresponding to a hooks library. For example, to set up two hooks libraries for the DHCPv4 server, the configuration would be: "Dhcp4": { : "hooks-libraries": [ { "library": "/opt/charging.so" }, { "library": "/opt/local/notification.so", "parameters": { "mail": "spam@example.com", "floor": 13, "debug": false, "users": [ "alice", "bob", "charlie" ], "languages": { "french": "bonjour", "klingon": "yl'el" } } } ] : } Note This is a change to the syntax used in Kea 0.9.2 and earlier, where hooks-libraries was a list of strings, each string being the name of a library. The change was made in Kea 1.0 to facilitate the specification of library-specific parameters, a capability available in Kea 1.1.0 onwards. Note The library reloading behavior has changed in Kea 1.1. Libraries are reloaded, even if their list hasn't changed. Kea does that, because the parameters specified for the library (or the files those parameters point to) may have changed. Libraries may have additional parameters. Those are not mandatory in the sense that there may be libraries that don't require them. However, for specific library there is often specific requirement for specify certain set of parameters. Please consult the documentation for your library for details. In the example above, the first library has no parameters. The second library has five parameters, specifying mail (string parameter), floor (integer parameter), debug (boolean parameter) and even lists (list of strings) and maps (containing strings). Nested parameters could be used if the library supports it. This topic is explained in detail in the Hooks Developer's Guide in the "Configuring Hooks Libraries" section. Notes: * The full path to each library should be given. * As noted above, order may be important - consult the documentation for each library. * An empty list has the same effect as omitting the hooks-libraries configuration element all together. Note There is one case where this is not true: if Kea is running with a configuration that contains a hooks-libraries item, and that item is removed and the configuration reloaded, the removal will be ignored and the libraries remain loaded. As a workaround, instead of removing the hooks-libraries item, change it to an empty list. This will be fixed in a future version of Kea. At the present time, only the kea-dhcp4 and kea-dhcp6 processes support hooks libraries. 13.3. Available Hooks Libraries As described above, the hooks functionality provides a way to customize a Kea server without modifying the core code. ISC has chosen to take advantage of this feature to provide functions that may only be useful to a subset of Kea users. To this end ISC has created some hooks libraries; these discussed in the following sections. Note Some of these libraries will be available with the base code while others will be shared with organizations supporting development of Kea , possibly as a 'benefit' or 'thank you' for helping to sustain the larger Kea project. If you would like to get access to those libraries, please consider taking out a support contract: this includes professional support, advance security notifications, input into our roadmap planning, and many other benefits, while helping making Kea sustainable in the long term. Currently the following libraries are available or planned from ISC: Table 13.1. List of available hooks libraries +------------------------------------------------------------------------+ | Name | Availability | Since | Description | |-------------+--------------+---------+---------------------------------| | | | | Reads known users list from a | | | | | file. Unknown users will be | | | | | assigned a lease from the last | | | | | subnet defined in the | | | | | configuration file, e.g. to | | | | | redirect them a captive portal. | | user_chk | Kea sources | Kea 0.8 | This demonstrates how an | | | | | external source of information | | | | | can be used to influence the | | | | | Kea allocation engine. This | | | | | hook is part of the Kea source | | | | | code and is available in the | | | | | src/hooks/dhcp/user_chk | | | | | directory. | |-------------+--------------+---------+---------------------------------| | | | | This library provides hooks | | | | | that record a detailed log of | | | | | lease assignments and renewals | | | | | into a set of log files. In | | | | | many legal jurisdictions | | | | | companies, especially ISPs, | | | | | must record information about | | | | | the addresses they have leased | | Forensic | Support | Kea | to DHCP clients. This library | | Logging | customers | 1.1.0 | is designed to help with that | | | | | requirement. If the information | | | | | that it records is sufficient | | | | | it may be used directly. If | | | | | your jurisdiction requires that | | | | | you save a different set of | | | | | information, you may use it as | | | | | a template or example and | | | | | create your own custom logging | | | | | hooks. | |-------------+--------------+---------+---------------------------------| | | | | Lightweight 4over6 (RFC 7596) | | | | | is a new IPv6 transition | | | | | technology that provides IPv4 | | | | | as a service in IPv6-only | | | | | network. It assumes that | | | | | dual-stack clients will get a | | | | | regular IPv6 address and IPv6 | | | | | prefix, but only a fraction of | | | | | an IPv4 address. The fraction | | | | | is specified as port-set, which | | | | | is essentially a range of TCP | | | | | and UDP ports a client can use. | | | | | By doing the transition on the | | | | | client side, this technology | | | | | eliminates the need to deploy | | | | | expensive Carrier Grade NATs | | Lightweight | Support | Autumn | within the operator's network. | | 4over6 | customers | 2016 | The problem on the DHCP side is | | | | | the non-trivial logic behind | | | | | it: each client needs to | | | | | receive an unique set of | | | | | lightweight 4over6 options (RFC | | | | | 7598), that include the IPv4 | | | | | address (shared among several | | | | | clients), port-set (which is | | | | | unique among clients sharing | | | | | the same IPv4 address) and a | | | | | number of additional | | | | | parameters. This hooks library | | | | | will generate values of those | | | | | options dynamically, thus | | | | | eliminating the need to | | | | | manually configure values for | | | | | each client separately. | +------------------------------------------------------------------------+ ISC hopes to see more hooks libraries become available as time progresses, both developed internally and externally. Since this list may evolve dynamically, we decided to keep it on a wiki page, available at this link: http://kea.isc.org/wiki/Hooks. If you are a developer or are aware of any hooks libraries not listed there, please send a note to the kea-users or kea-dev mailing lists and someone will update it. 13.3.1. user_chk: Checking User Access The user_chk library is the first hooks library published by ISC. It attempts to serve several purposes: * To assign "new" or "unregistered" users to a restricted subnet, while "known" or "registered" users are assigned to unrestricted subnets. * To allow DHCP response options or vendor option values to be customized based upon user identity. * To provide a real time record of the user registration activity which can be sampled by an external consumer. * To serve as a demonstration of various capabilities possible using the hooks interface. Once loaded, the library allows segregating incomings requests into known and unknown clients. For known clients, the packets are processed mostly as usual, except it is possible to override certain options being sent. That can be done on a per host basis. Clients that are not on the known hosts list will be treated as unknown and will be assigned to the last subnet defined in the configuration file. As an example of use, this behavior may be used to put unknown users into a separate subnet that leads to a walled garden, where they can only access a registration portal. Once they fill in necessary data, their details are added to the known clients file and they get a proper address after their device is restarted. Note This library was developed several years before the host reservation mechanism has become available. Currently host reservation is much more powerful and flexible, but nevertheless the user_chk capability to consult and external source of information about clients and alter Kea's behavior is useful and remains of educational value. The library reads the /tmp/user_chk_registry.txt file while being loaded and each time an incoming packet is processed. The file is expected to have each line contain a self-contained JSON snippet which must have the following two entries: * type, whose value is "HW_ADDR" for IPv4 users or "DUID" for IPv6 users * id, whose value is either the hardware address or the DUID from the equest formatted as a string of hex digits, with or without ":" delimiters. and may have the zero or more of the following entries: * bootfile whose value is the pathname of the desired file * tftp_server whose value is the hostname or IP address of the desired server A sample user registry file is shown below: { "type" : "HW_ADDR", "id" : "0c:0e:0a:01:ff:04", "bootfile" : "/tmp/v4bootfile" } { "type" : "HW_ADDR", "id" : "0c:0e:0a:01:ff:06", "tftp_server" : "tftp.v4.example.com" } { "type" : "DUID", "id" : "00:01:00:01:19:ef:e6:3b:00:0c:01:02:03:04", "bootfile" : "/tmp/v6bootfile" } { "type" : "DUID", "id" : "00:01:00:01:19:ef:e6:3b:00:0c:01:02:03:06", "tftp_server" : "tftp.v6.example.com" } As with any other hooks libraries provided by ISC, internals of the user_chk code are well documented. You can take a look at the Kea Developer's Guide section dedicated to the user_chk library that discusses how the code works internally. That, together with our general entries in Hooks Framework section should give you some pointers how to extend this library and perhaps even write your own from scratch. 13.3.2. Forensic Logging Hooks This section describes the forensic log hooks library. This library povides hooks that record a detailed log of lease assignments and renewals into a set of log files. Currently this library is only available to ISC customers with a support contract. In many legal jurisdictions companies, especially ISPs, must record information about the addresses they have leased to DHCP clients. This library is designed to help with that requirement. If the information that it records is sufficient it may be used directly. If your jurisdiction requires that you save a different set of information you may use it as a template or example and create your own custom logging hooks. This logging is done as a set of hooks to allow it to be customized to any particular need. Modifying a hooks library is easier and safer than updating the core code. In addition by using the hooks features those users who don't need to log this information can leave it out and avoid any performance penalties. 13.3.2.1. Log File Naming The names for the log files have the following form: path/base-name.CCYYMMDD.txt The "path" and "base-name" are supplied in the configuration as described below see Section 13.3.2.4, "Configuring the Forensic Log Hooks". The next part of the name is the date the log file was started, with four digits for year, two digits for month and two digits for day. The file is rotated on a daily basis. Note When running Kea servers for both DHCPv4 and DHCPv6 the log names must be distinct. See the examples in Section 13.3.2.4, "Configuring the Forensic Log Hooks". 13.3.2.2. DHCPv4 Log Entries For DHCPv4 the library creates entries based on DHCPREQUEST messages and corresponding DHCPv4 leases intercepted by lease4_select (for new leases) and lease4_renew (for renewed leases) hooks. An entry is a single string with no embedded end-of-line markers and has the following sections: address duration device-id {client-info} {relay-info} Where: * address - the leased IPv4 address given out and whether it was assigned or renewed. * duration - the lease lifetime expressed in days (if present), hours, minutes and seconds. A lease lifetime of 0xFFFFFFFF will be denoted with the text "infinite duration". * device-id - the client's hardware address shown as numerical type and hex digit string. * client-info - the DHCP client id option (61) if present, shown as a hex string. * relay-info - for relayed packets the giaddr and the RAI circuit id and remote id options (option 82 sub options 1 and 2) if present. The circuit id and remote id are presented as hex strings For instance (line breaks added for readability, they would not be present in the log file). Address: 192.2.1.100 has been renewed for 1 hrs 52 min 15 secs to a device with hardware address: hwtype=1 08:00:2b:02:3f:4e, client-id: 17:34:e2:ff:09:92:54 connected via relay at address: 192.2.16.33, identified by circuit-id: 68:6f:77:64:79 and remote-id: 87:f6:79:77:ef 13.3.2.3. DHCPv6 Log Entries For DHCPv6 the library creates entries based on lease management actions intercepted by the lease6_select (for new leases), lease6_renew (for renewed leases) and lease6_rebind (for rebound leases). An entry is a single string with no embedded end-of-line markers and has the following sections: address duration device-id {relay-info}* Where: * address - the leased IPv6 address or prefix given out and whether it was assigned or renewed. * duration - the lease lifetime expressed in days (if present), hours, minutes and seconds. A lease lifetime of 0xFFFFFFFF will be denoted with the text "infinite duration". * device-id - the client's DUID and hardware address (if present). * relay-info - for relayed packets the content of relay agent messages, remote id and subscriber id options (x and xx) if present. For instance (line breaks added for readability, they would not be present in the log file). Address:2001:db8:1:: has been assigned for 0 hrs 11 mins 53 secs to a device with DUID: 17:34:e2:ff:09:92:54 and hardware address: hwtype=1 08:00:2b:02:3f:4e (from Raw Socket) connected via relay at address: fe80::abcd for client on link address: 3001::1, hop count: 1, identified by remote-id: 01:02:03:04:0a:0b:0c:0d:0e:0f and subscriber-id: 1a:2b:3c:4d:5e:6f 13.3.2.4. Configuring the Forensic Log Hooks To use this functionality the hook library must be included in the configuration of the desired DHCP server modules. The legal_log library is installed alongside the Kea libraries in [kea-install-dir]/lib where kea-install-dir is determined by the "--prefix" option of the configure script. It defaults to /usr/local. Assuming the default value then, configuring kea-dhcp4 to load the legal_log library could be done with the following Kea4 configuration: "Dhcp4": { "hooks-libraries": [ { "library": "/usr/local/lib/libdhcp_legal_log.so", "parameters": { "path": "/var/kea/var", "base-name": "kea-forensic4" } }, ... ] } To configure it for kea-dhcp6, the commands are simply as shown below: "Dhcp6": { "hooks-libraries": [ { "library": "/usr/local/lib/libdhcp_legal_log.so", "parameters": { "path": "/var/kea/var", "base-name": "kea-forensic6" } }, ... ] } Two Hook Library parameters are supported: * path - the directory in which the forensic file(s) will be written. The default value is [prefix]/kea/var. The directory must exist. * base-name - an arbitrary value which is used in conjunction with the current system date to form the current foresnic file name. It defaults to kea-legal. Chapter 14. Statistics Table of Contents 14.1. Statistics Overview 14.2. Statistics Lifecycle 14.3. Commands for Manipulating Statistics 14.3.1. statistic-get command 14.3.2. statistic-reset command 14.3.3. statistic-remove command 14.3.4. statistic-get-all command 14.3.5. statistic-reset-all command 14.3.6. statistic-remove-all command 14.1. Statistics Overview Both Kea DHCP servers support statistics gathering. A working DHCP server encounters various events that can cause certain statistics to be collected. For example, a DHCPv4 server may receive a packet (pkt4-received statistic increases by one) that after parsing was identified as a DHCPDISCOVER (pkt4-discover-received). The Server processed it and decided to send a DHCPOFFER representing its answer (pkt4-offer-sent and pkt4-sent statistics increase by one). Such events happen frequently, so it is not uncommon for the statistics to have values in high thousands. They can serve as an easy and powerful tool for observing a server's and network's health. For example, if pkt4-received statistic stops growing, it means that the clients' packets are not reaching the server. There are four types of statistics: * integer - this is the most common type. It is implemented as 64 bit integer (int64_t in C++), so it can hold any value between -2^63 to 2^63 -1. * floating point - this type is intended to store floating point precision. It is implemented as double C++ type. * duration - this type is intended for recording time periods. It uses boost::posix_time::time_duration type, which stores hours, minutes, seconds and microseconds. * string - this type is intended for recording statistics in textual form. It uses std::string C++ type. During normal operation, DHCPv4 and DHCPv6 servers gather statistics. For a list of DHCPv4 and DHCPv6 statistics, see Section 7.7, "Statistics in the DHCPv4 Server" and Section 8.11, "Statistics in the DHCPv6 Server", respectively. To extract data from the statistics module, the control channel can be used. See Chapter 15, Management API for details. It is possible to retrieve a single or all statistics, reset statistics (i.e. set to neutral value, typically zero) or even remove completely a single or all statistics. See section Section 14.3, "Commands for Manipulating Statistics" for a list of statistic oriented commands. 14.2. Statistics Lifecycle It is useful to understand how the Statistics Manager module works. When the server starts operation, the manager is empty and does not have any statistics. When statistic-get-all is executed, an empty list is returned. Once the server performs an operation that causes a statistic to change, the related statistic will be created. In the general case, once a statistic is recorded even once, it is kept in the manager, until explicitly removed, by statistic-remove or statistic-remove-all being called or the server is shut down. Per subnet statistics are explicitly removed when reconfiguration takes place. Statistics are considered run-time properties, so they are not retained after server restart. Removing a statistic that is updated frequently makes little sense as it will be re-added when the server code next records that statistic. The statistic-remove and statistic-remove-all commands are intended to remove statistics that are not expected to be observed in the near future. For example, a misconfigured device in a network may cause clients to report duplicate addresses, so the server will report increasing values of pkt4-decline-received. Once the problem is found and the device is removed, the system administrator may want to remove the pkt4-decline-received statistic, so it won't be reported anymore. If a duplicate address is detected ever again, the server will add this statistic back. 14.3. Commands for Manipulating Statistics There are several commands defined that can be used for accessing (-get), resetting to zero or neutral value (-reset) or even removing a statistic completely (-remove). The difference between reset and remove is somewhat subtle. The reset command sets the value of the statistic to zero or neutral value. After this operation, the statistic will have a value of 0 (integer), 0.0 (float), 0h0m0s0us (duration) or "" (string). When asked for, a statistic with the values mentioned will be returned. Remove removes a statistic completely, so the statistic will not be reported anymore. Please note that the server code may add it back if there's a reason to record it. Note The following sections describe commands that can be sent to the server: the examples are not fragments of a configuration file. For more information on sending commands to Kea, see Chapter 15, Management API. 14.3.1. statistic-get command statistic-get command retrieves a single statistic. It takes a single string parameter called name that specifies the statistic name. An example command may look like this: { "command": "statistic-get", "arguments": { "name": "pkt4-received" } } The server will respond with details of the requested statistic, with result set to 0 indicating success and the specified statistic as the value of "arguments" parameter. If the requested statistic is not found, the response will contain an empty map, i.e. only { } as argument, but the status code will still be set to success (0). 14.3.2. statistic-reset command statistic-reset command sets the specified statistic to its neutral value: 0 for integer, 0.0 for float, 0h0m0s0us for time duration and "" for string type. It takes a single string parameter called name that specifies the statistic name. An example command may look like this: { "command": "statistic-reset", "arguments": { "name": "pkt4-received" } } If the specific statistic is found and reset was successful, the server will respond with a status of 0, indicating success and an empty parameters field. If an error is encountered (e.g. requested statistic was not found), the server will return a status code of 1 (error) and the text field will contain the error description. 14.3.3. statistic-remove command statistic-remove command attempts to delete a single statistic. It takes a single string parameter called name that specifies the statistic name. An example command may look like this: { "command": "statistic-remove", "arguments": { "name": "pkt4-received" } } If the specific statistic is found and its removal was successful, the server will respond with a status of 0, indicating success and an empty parameters field. If an error is encountered (e.g. requested statistic was not found), the server will return a status code of 1 (error) and the text field will contain the error description. 14.3.4. statistic-get-all command statistic-get-all command retrieves all statistics recorded. An example command may look like this: { "command": "statistic-get-all", "arguments": { } } The server will respond with details of all recorded statistics, with result set to 0 indicating that it iterated over all statistics (even when the total number of statistics is zero). 14.3.5. statistic-reset-all command statistic-reset command sets all statistics to their neutral values: 0 for integer, 0.0 for float, 0h0m0s0us for time duration and "" for string type. An example command may look like this: { "command": "statistic-reset-all", "arguments": { } } If the operation is successful, the server will respond with a status of 0, indicating success and an empty parameters field. If an error is encountered, the server will return a status code of 1 (error) and the text field will contain the error description. 14.3.6. statistic-remove-all command statistic-remove-all command attempts to delete all statistics. An example command may look like this: { "command": "statistic-remove-all", "arguments": { } } If the removal of all statistics was successful, the server will respond with a status of 0, indicating success and an empty parameters field. If an error is encountered, the server will return a status code of 1 (error) and the text field will contain the error description. Chapter 15. Management API Table of Contents 15.1. Data Syntax 15.2. Using the Control Channel 15.3. Commands Supported by Both the DHCPv4 and DHCPv6 Servers 15.3.1. leases-reclaim 15.3.2. list-commands 15.3.3. shutdown A classic approach to daemon configuration assumes that the server's configuration is stored in configuration files and, when the configuration is changed, the daemon is restarted. This approach has the significant disadvantage of introducing periods of downtime, when client traffic is not handled. Another risk is that if the new configuration is invalid for whatever reason, the server may refuse to start, which will further extend the downtime period until the issue is resolved. To avoid such problems, both the DHCPv4 and DHCPv6 servers include support for a mechanism that allows on-line reconfiguration without requiring server shutdown. Both servers can be instructed to open control sockets, which is a communication channel. The server is able to receive commands on that channel, act on them and report back status. While the set of commands in Kea 1.1.0 is limited, the number is expected to grow over time. Currently the only supported type of control channel is UNIX stream socket. For details how to configure it, see Section 7.8, "Management API for the DHCPv4 Server" and Section 8.12, "Management API for the DHCPv6 Server". It is likely that support for other control channel types will be added in the future. 15.1. Data Syntax Communication over the control channel is conducted using JSON structures. If configured, Kea will open a socket and listen for incoming connections. A process connecting to this socket is expected to send JSON commands structured as follows: { "command": "foo", "arguments": { "param1": "value1", "param2": "value2", ... } } command is the name of command to execute and is mandatory. arguments is a map of parameters required to carry out the given command. The exact content and format of the map is command specific. The server will process the incoming command and then send a response of the form: { "result": 0|1, "text": "textual description", "arguments": { "argument1": "value1", "argument2": "value2", ... } } result indicates the outcome of the command. A value of 0 means success while any non-zero value designates an error. Currently 1 is used as a generic error, but additional error codes may be added in the future. The text field typically appears when result is non-zero and contains a description of the error encountered, but it may also appear for successful results (that is command specific). arguments is a map of additional data values returned by the server which is specific to the command issued. The map is always present, even if it contains no data values. 15.2. Using the Control Channel Kea does not currently provide a client for using the control channel. The primary reason for this is the expectation is that the entity using the control channel is typically an IPAM or similar network management/monitoring software which may have quite varied expectations regarding the client and is even likely to be written in languages different than C or C++. Therefore only examples are provided to show how one can take advantage of the API. The easiest way is to use a tool called socat, a tool available from socat homepage, but it is also widely available in Linux and BSD distributions. Once Kea is started, one could connect to the control interface using the following command: $ socat UNIX:/path/to/the/kea/socket - where /path/to/the/kea/socket is the path specified in the Dhcp4/control-socket/socket-name parameter in the Kea configuration file. Text passed to socat will be sent to Kea and the responses received from Kea printed to standard output. It is also easy to open UNIX socket programmatically. An example of such a simplistic client written in C is available in the Kea Developer's Guide, chapter Control Channel Overview, section Using Control Channel. 15.3. Commands Supported by Both the DHCPv4 and DHCPv6 Servers 15.3.1. leases-reclaim leases-reclaim command instructs the server to reclaim all expired leases immediately. The command has the following JSON syntax: { "command": "leases-reclaim", "arguments": { "remove": true } } The remove boolean parameter is mandatory and it indicates whether the reclaimed leases should be removed from the lease database (if true), or they should be left in the expired-reclaimed state (if false). The latter facilitates lease affinity, i.e. ability to re-assign expired lease to the same client which used this lease before. See Section 9.3, "Configuring Lease Affinity" for the details. Also, see Section 9.1, "Lease Reclamation" for the general information about the processing of expired leases (leases reclamation). 15.3.2. list-commands The list-commands command retrieves a list of all commands supported by the server. It does not take any arguments. An example command may look like this: { "command": "list-commands", "arguments": { } } The server will respond with a list of all supported commands. The arguments element will be a list of strings. Each string will convey one supported command. 15.3.3. shutdown The shutdown command instructs the server to initiate its shutdown procedure. It is the equivalent of sending a SIGTERM signal to the process. This command does not take any arguments. An example command may look like this: { "command": "shutdown", "arguments": { } } The server will respond with a confirmation that the shutdown procedure has been initiated. Chapter 16. The libdhcp++ Library Table of Contents 16.1. Interface detection and Socket handling libdhcp++ is a library written in C++ that handles many DHCP-related tasks, including: * DHCPv4 and DHCPv6 packets parsing, manipulation and assembly * Option parsing, manipulation and assembly * Network interface detection * Socket operations such as creation, data transmission and reception and socket closing. While this library is currently used by Kea, it is designed to be a portable, universal library, useful for any kind of DHCP-related software. 16.1. Interface detection and Socket handling Both the DHCPv4 and DHCPv6 components share network interface detection routines. Interface detection is currently supported on Linux, all BSD family (FreeBSD, NetBSD, OpenBSD), Mac OS X and Solaris 11 systems. DHCPv4 requires special raw socket processing to send and receive packets from hosts that do not have IPv4 address assigned. Support for this operation is implemented on Linux, FreeBSD, NetBSD and OpenBSD. It is likely that DHCPv4 component will not work in certain cases on other systems. Chapter 17. Logging Table of Contents 17.1. Logging Configuration 17.1.1. Loggers 17.1.2. Logging Message Format 17.1.3. Logging During Kea Startup 17.1. Logging Configuration During its operation Kea may produce many messages. They differ in severity (some are more important than others) and source (some are produced by specific components, e.g. hooks). It is useful to understand which log messages are needed and which are not, and configure your logging appropriately. For example, debug level messages can be safely ignored in a typical deployment. They are, however, very useful when debugging a problem. The logging system in Kea is configured through the Logging section in your configuration file. All daemons (e.g. DHCPv4 and DHCPv6 servers) will use the configuration in the Logging section to see what should be logged and to where. This allows for sharing identical logging configuration between daemons. 17.1.1. Loggers Within Kea, a message is logged through an entity called a "logger". Different components log messages through different loggers, and each logger can be configured independently of one another. Some components, in particular the DHCP server processes, may use multiple loggers to log messages pertaining to different logical functions of the component. For example, the DHCPv4 server uses one logger for messages pertaining to packet reception and transmission, another logger for messages related to lease allocation and so on. Some of the libraries used by the Kea servers, e.g. libdhcpsrv, use their own loggers. Users implementing hooks libraries (code attached to the server at runtime) are responsible for creating the loggers used by those libraries. Such loggers should have unique names, different from the logger names used by Kea. In this way the messages output by the hooks library can be distingued from messages issued by the core Kea code. Unique names also allow the loggers to be configured independently of loggers used by Kea. Whenever it makes sense, a hook library can use multiple loggers to log messages pertaining to different logical parts of the library. In the Logging section of a configuration file you can specify the configuration for zero or more loggers (including loggers used by the proprietary hooks libraries). If there are no loggers specified, the code will use default values: these cause Kea to log messages of INFO severity or greater to standard output. There is also a small time window after Kea has been started, but has not yet read its configuration. Logging in this short period can be controlled using environment variables. For details, see Section 17.1.3, "Logging During Kea Startup". The three main elements of a logger configuration are: name (the component that is generating the messages), the severity (what to log), and the output_commands (where to log). There is also a debuglevel element, which is only relevant if debug-level logging has been selected. 17.1.1.1. name (string) Each logger in the system has a name, the name being that of the component binary file using it to log messages. For instance, if you want to configure logging for the DHCPv4 server, you add an entry for a logger named "kea-dhcp4". This configuration will then be used by the loggers in the DHCPv4 server, and all the libraries used by it (unless a library defines its own logger and there is specific logger configuration that applies to that logger). When tracking down an issue with the server's operation, use of DEBUG logging is required to obtain the verbose output needed for problems diagnosis. However, the high verbosity is likely to overwhelm the logging system in cases when the server is processing high volume traffic. To mitigate this problem, use can be made of the fact that Kea uses multiple loggers for different functional parts of the server and that each of these can be configured independently. If the user is reasonably confident that a problem originates in a specific function of the server, or that the problem is related to the specific type of operation, they may enable high verbosity only for the relevant logger, so limiting the debug messages to the required minimum. The loggers are associated with a particular library or binary of Kea. However, each library or binary may (and usually does) include multiple loggers. For example, the DHCPv4 server binary contains separate loggers for: packet parsing, for dropped packets, for callouts etc. The loggers form a hierarchy. For each program in Kea, there is a "root" logger, named after the program (e.g. the root logger for kea-dhcp (the DHCPv4 server) is named kea-dhcp4. All other loggers are children of this logger, and are named accordingly, e.g. the the allocation engine in the DHCPv4 server logs messages using a logger called kea-dhcp4.alloc-engine. This relationship is important as each child logger derives its default configuration from its parent root logger. In the typical case, the root logger configuration is the only logging configuration specified in the configuration file and so applies to all loggers. If an entry is made for a given logger, any attributes specified override those of the root logger, whereas any not specified are inherited from it. To illustrate this, suppose you are using the DHCPv4 server with the root logger "kea-dhcp4" logging at the INFO level. In order to enable DEBUG verbosity for the DHCPv4 packet drops, you must create configuration entry for the logger called "kea-dhcp4.bad-packets" and specify severity DEBUG for this logger. All other configuration parameters may be omited for this logger if the logger should use the default values specified in the root logger's configuration. If there are multiple logger specifications in the configuration that might match a particular logger, the specification with the more specific logger name takes precedence. For example, if there are entries for both "kea-dhcp4" and "kea-dhcp4.dhcpsrv", the DHCPv4 server -- and all libraries it uses that are not dhcpsrv -- will log messages according to the configuration in the first entry ("kea-dhcp4"). Currently defined loggers are: * kea-dhcp4 - the root logger for the DHCPv4 server. All components used by the DHCPv4 server inherit the settings from this logger. * kea-dhcp4.alloc-engine - used by the lease allocation engine, which is responsible for managing leases in the lease database, i.e. create, modify and remove DHCPv4 leases as a result of processing messages from the clients. * kea-dhcp4.bad-packets - used by the DHCPv4 server daemon for logging inbound client packets that were dropped or to which the server responded with a DHCPNAK. It allows administrators to configure a separate log output that contains only packet drop and reject entries. * kea-dhcp4.callouts - used to log messages pertaining to the callouts registration and execution for the particular hook point. * kea-dhcp4.commands - used to log messages relating to the handling of commands received by the the DHCPv4 server over the command channel. * kea-dhcp4.ddns - used by the DHCPv4 server to log messages related to the Client FQDN and Hostname option processing. It also includes log messages related to the relevant DNS updates. * kea-dhcp4.dhcp4 - used by the DHCPv4 server daemon to log basic operations. * kea-dhcp4.dhcpsrv - the base logger for the libdhcpsrv library. * kea-dhcp4.eval - used to log messages relating to the client classification expression evaluation code. * kea-dhcp4.hooks - used to log messages related to management of hooks libraries, e.g. registration and deregistration of the libraries, and to the initialization of the callouts execution for various hook points within the DHCPv4 server. * kea-dhcp4.hosts - used within the libdhcpsrv and it logs messages related to the management of the DHCPv4 host reservations, i.e. retrieval of the reservations and adding new reservations. * kea-dhcp4.leases - used by the DHCPv4 server to log messages related to the lease allocation. The messages include detailed information about the allocated or offered leases, errors during the lease allocation etc. * kea-dhcp4.options - used by the DHCPv4 server to log messages related to processing of the options in the DHCPv4 messages, i.e. parsing options, encoding options into on-wire format and packet classification using options contained in the received packets. * kea-dhcp4.packets - this logger is mostly used to log messages related to transmission of the DHCPv4 packets, i.e. packet reception and sending a response. Such messages include information about the source and destination IP addresses and interfaces used to transmit packets. The logger is also used to log messages related to subnet selection, as this selection is usually based on the IP addresses and/or interface names, which can be retrieved from the received packet, even before the DHCPv4 message carried in the packet is parsed. * kea-dhcp6 - the root logger for the DHCPv6 server. All components used by the DHCPv6 server inherit the settings from this logger if there is no specialized logger provided. * kea-dhcp6.alloc-engine - used used by the lease allocation engine, which is responsible for managing leases in the lease database, i.e. create, modify and remove DHCPv6 leases as a result of processing messages from the clients. * kea-dhcp6.bad-packets - used used by the DHCPv6 server daemon for logging inbound client packets that were dropped. * kea-dhcp6.callouts - used to log messages pertaining to the callouts registration and execution for the particular hook point. * kea-dhcp6.commands - used to log messages relating to the handling of commands received by the the DHCPv6 server over the command channel. * kea-dhcp6.ddns - this logger is used by the DHCPv6 server to log messages related to the Client FQDN option processing. It also includes log messages related to the relevant DNS updates. * kea-dhcp6.dhcp6 - used DHCPv6 server daemon to log basic operations. * kea-dhcp6.dhcpsrv - the base logger for the libdhcpsrv library. * kea-dhcp6.eval - used to log messages relating to the client classification expression evaluation code. * kea-dhcp6.hooks - this logger is used to log messages related to management of hooks libraries, e.g. registration and deregistration of the libraries, and to the initialization of the callouts execution for various hook points within the DHCPv6 server. * kea-dhcp6.hosts - used within the libdhcpsrv and it logs messages related to the management of the DHCPv6 host reservations, i.e. retrieval of the reservations and adding new reservations. * kea-dhcp6.leases - used by the DHCPv6 server to log messages related to the lease allocation. The messages include detailed information about the allocated or offered leases, errors during the lease allocation etc. * kea-dhcp6.options - used by the DHCPv6 server to log messages related to processing of the options in the DHCPv6 messages, i.e. parsing options, encoding options into on-wire format and packet classification using options contained in the received packets. * kea-dhcp6.packets - this logger is mostly used to log messages related to transmission of the DHCPv6 packets, i.e. packet reception and sending a response. Such messages include the information about the source and destination IP addresses and interfaces used to transmit packets. This logger is also used to log messages related to subnet selection, as this selection is usually based on the IP addresses and/or interface names, which can be retrieved from the received packet, even before the DHCPv6 message carried in the packet is parsed. * kea-dhcp-ddns - the root logger for the kea-dhcp-ddns daemon. All components used by this daemon inherit the settings from this logger if there is no specialized logger provided. * kea-dhcp-ddns.dhcpddns - the logger used by the kea-dhcp-ddns daemon for logging configuration and global event information. This logger does not specify logging settings for libraries used by the daemon. * kea-dhcp-ddns.dhcp-to-d2 - used by the kea-dhcp-ddns daemon for logging information about events dealing with receiving messages from the DHCP servers and adding them to the queue for processing. * kea-dhcp-ddns.d2-to-dns - used by the kea-dhcp-ddns daemon for logging information about events dealing with sending and receiving messages with the DNS servers. Note that user-defined hook libraries should not use any of those loggers but should define new loggers with names that correspond to the libraries using them. Suppose that the user created the library called "libpacket-capture" to dump packets received and transmitted by the server to the file. The appropriate name for the logger could be kea-dhcp4.packet-capture. (Note that the hook library implementor only specifies the second part of this name, i.e. "packet-capture". The first part is a root logger name and is prepended by the Kea logging system.) It is also important to note that since this new logger is a child of a root logger, it inherits the configuration from the root logger, something that can be overridden by an entry in the configuration file. The list of loggers above excludes any loggers implemented in hooks libraries. Please consult the documentation for the libraries for the names of the loggers they define. Additional loggers may be defined in future versions of Kea. The easiest way to find out the logger name is to configure all logging to go to a single destination and look for specific logger names. See Section 17.1.2, "Logging Message Format" for details. 17.1.1.2. severity (string) This specifies the category of messages logged. Each message is logged with an associated severity which may be one of the following (in descending order of severity): * FATAL - associated with messages generated by a condition that is so serious that the server cannot continue executing. * ERROR- associated with messages generated by an error condition. The server will continue executing, but the results may not be as expected. * WARN - indicates an out of the ordinary condition. However, the server will continue executing normally. * INFO - an informational message marking some event. * DEBUG - messages produced for debugging purposes. When the severity of a logger is set to one of these values, it will only log messages of that severity and above (e.g. setting the logging severity to INFO will log INFO, WARN, ERROR and FATAL messages). The severity may also be set to NONE, in which case all messages from that logger are inhibited. Note The keactrl tool, described in Chapter 6, Managing Kea with keactrl, can be configured to start the servers in the verbose mode. If this is the case, the settings of the logging severity in the configuration file will have no effect, i.e. the servers will use logging severity of DEBUG regardless of the logging settings specified in the configuration file. If you need to control severity via configuration file, please make sure that the kea_verbose value is set to "no" within the keactrl configuration. 17.1.1.3. debuglevel (integer) When a logger's severity is set to DEBUG, this value specifies what level of debug messages should be printed. It ranges from 0 (least verbose) to 99 (most verbose). If severity for the logger is not DEBUG, this value is ignored. 17.1.1.4. output_options (list) Each logger can have zero or more output_options. These specify where log messages are sent. These are explained in detail below. 17.1.1.4.1. output (string) This value determines the type of output. There are several special values allowed here: stdout (messages are printed on standard output), stderr (messages are printed on stderr), syslog (messages are logged to syslog using default name, syslog:name (messages are logged to syslog using specified name). Any other value is interpreted as a filename to which messages should be written. 17.1.1.4.2. flush (true of false) Flush buffers after each log message. Doing this will reduce performance but will ensure that if the program terminates abnormally, all messages up to the point of termination are output. The default is "true". 17.1.1.4.3. maxsize (integer) Only relevant when destination is file, this is maximum file size of output files in bytes. When the maximum size is reached, the file is renamed and a new file opened. (For example, a ".1" is appended to the name -- if a ".1" file exists, it is renamed ".2", etc.) If this is set to 0 or omitted, no maximum file size is used. Note Due to a limitation of the underlying logging library (log4cplus), rolling over the log files (from ".1" to ".2", etc) may show odd results: There can be multiple small files at the timing of roll over. This can happen when multiple processes try to roll over the files simultaneously. Version 1.1.0 of log4cplus solved this problem, so if this version or later of log4cplus is used to build Kea, it should not happen. Even for older versions it is normally expected to happen rarely unless the log messages are produced very frequently by multiple different processes. 17.1.1.4.4. maxver (integer) Maximum number of old log files to keep around when rolling the output file. Only relevant when output is "file". 17.1.1.5. Example Logger Configurations In this example we want to set the global logging to write to the console using standard output. "Logging": { "loggers": [ { "name": "kea-dhcp4", "output_options": [ { "output": "stdout" } ], "severity": "WARN" } ] } In this second example, we want to store debug log messages in a file that is at most 2MB and keep up to 8 copies of old logfiles. Once the logfile grows to 2MB, it will be renamed and a new file file be created. "Logging": { "loggers": [ { "name": "kea-dhcp6", "output_options": [ { "output": "/var/log/kea-debug.log", "maxver": 8, "maxsize": 204800, "flush": true } ], "severity": "DEBUG", "debuglevel": 99 } ] } 17.1.2. Logging Message Format Each message written to the configured logging destinations comprises a number of components that identify the origin of the message and, if the message indicates a problem, information about the problem that may be useful in fixing it. Consider the message below logged to a file: 2014-04-11 12:58:01.005 INFO [kea-dhcp4.dhcpsrv/27456] DHCPSRV_MEMFILE_DB opening memory file lease database: type=memfile universe=4 Note: the layout of messages written to the system logging file (syslog) may be slightly different. This message has been split across two lines here for display reasons; in the logging file, it will appear on one line. The log message comprises a number of components: 2014-04-11 12:58:01.005 The date and time at which the message was generated. INFO The severity of the message. [kea-dhcp4.dhcpsrv/27456] The source of the message. This comprises two elements: the Kea process generating the message (in this case, kea-dhcp4) and the component within the program from which the message originated (dhcpsrv, which is the name of the common library used by DHCP server implementations). The number after the slash is a process id (pid). DHCPSRV_MEMFILE_DB The message identification. Every message in Kea has a unique identification, which can be used as an index into the Kea Messages Manual (http://kea.isc.org/docs/kea-messages.html) from which more information can be obtained. opening memory file lease database: type=memfile universe=4 A brief description. Within this text, information relating to the condition that caused the message to be logged will be included. In this example, the information is logged that the in-memory lease database backend will be used to store DHCP leases. 17.1.3. Logging During Kea Startup The logging configuration is specified in the configuration file. However, when Kea starts, the file is not read until some way into the initialization process. Prior to that, the logging settings are set to default values, although it is possible to modify some aspects of the settings by means of environment variables. Note that in the absence of any logging configuration in the configuration file, the settings of (possibly modified) default configuration will persist while the program is running. The following environment variables can be used to control the behavior of logging during startup: KEA_LOCKFILE_DIR Specifies a directory where the logging system should create its lock file. If not specified, it is prefix/var/run/kea, where prefix defaults to /usr/local. This variable must not end with a slash. There is one special value: "none", which instructs Kea to not create lock file at all. This may cause issues if several processes log to the same file. KEA_LOGGER_DESTINATION Specifies logging output. There are several special values. stdout Log to standard output. stderr Log to standard error. syslog[:fac] Log via syslog. The optional fac (which is separated from the word "syslog" by a colon) specifies the facility to be used for the log messages. Unless specified, messages will be logged using the facility "local0". Any other value is treated as a name of the output file. If not specified otherwise, Kea will log to standard output. Chapter 18. Frequently Asked Questions Table of Contents 18.1. General Frequently Asked Questions 18.1.1. Where did the Kea name came from? 18.1.2. Feature X is not supported yet. When/if will it be available? 18.2. Frequently Asked Questions about DHCPv4 18.2.1. I set up a firewall, but the Kea server still receives the traffic. Why? 18.3. Frequently Asked Questions about DHCPv6 18.3.1. Kea DHCPv6 doesn't seem to get incoming traffic. I checked with tcpdump (or other traffic capture software) that the incoming traffic is reaching the box. What's wrong? This chapter contains a number of frequently asked questions and troubleshooting tips. It currently lacks content, but it is expected to grow over time. 18.1. General Frequently Asked Questions 18.1.1. Where did the Kea name came from? Kea is the name of a high mountain parrot living in New Zealand. See this https://lists.isc.org/pipermail/kea-users/2014-October/000032.html for an extended answer. 18.1.2. Feature X is not supported yet. When/if will it be available? Kea is developed by a small team of engineers. Our resources are limited, so we need to prioritize requests. The complexity of a new feature (how difficult it is to implement a feature and how likely it would break something that already works), amount of work required and expected popularity (i.e., how many users would actually benefit from it) are three leading factors. We sometimes also have contractual obligations. Simply stating that you'd like feature X is useful. We try to implement features that are actively requested first, but the reality is that we have more requests than we can handle, so some of them must be postponed, at least in the near future. So is your request likely to be rejected? Not at all. You can do many things to greatly improve the chances of your request being fulfilled. First, it helps to explain why you need a feature. If your explanation is reasonable and there are likely other users that would benefit from it, the chances for Kea developers to put this task on a roadmap is better. Saying that you are willing to participate in tests (e.g., test engineering drops when they become available) is also helpful. Another thing you can do to greatly improve the chances of a feature to appear is to actually develop it on your own and submit a patch. That's an avenue that people often forget about. Kea is open source software and we do accept patches. There are certain requirements, like code quality, comments, unit-tests, documentation, etc., but we have accepted a significant number of patches in the past, so it's doable. Accepted contributions range from minor documentation corrections to significant new features, like support for a new database type. Before considering writing and submitting a patch, make sure you read the Contributor's Guide in the Kea Developer's Guide. Kea is developed by ISC, which is a non-profit organization. You may consider signing a development contract with us. In the past we did implement certain features due to contractual obligations. With additional funds we are able to put extra engineering efforts into Kea development. We can reshuffle our schedule or add extra hands to the team if needed. Please keep in mind that Kea is open source software and its principle goal is to provide a good DHCP solution that can be used by everyone. In other words, we may refuse a contract that would tie the solution to specific proprietary technology or make it unusable for other users. Also, we strive to make Kea a reference implementation, so if your proposal significantly violates a RFC, we may have a problem with that. Nevertheless, please talk to us and we may be able to find a solution. Finally, Kea has a public roadmap, with releases happening several times each year. We tend to not modify plans for the current milestone, unless there are very good reasons to do so. Therefore "I'd like a feature X in 6 months" is much better received than "I'd like a feature X now". 18.2. Frequently Asked Questions about DHCPv4 18.2.1. I set up a firewall, but the Kea server still receives the traffic. Why? Any DHCPv4 server must be able to receive from and send traffic to hosts that don't have an IPv4 address assigned yet. That is typically not possible with regular UDP sockets, therefore the Kea DHCPv4 server uses raw sockets by default. Raw sockets mean that the incoming packets are received as raw Ethernet frames, thus bypassing the whole kernel IP stack, including any firewalling rules your kernel may provide. If you do not want the server to use raw sockets, it is possible to configure the Kea DHCPv4 server to use UDP sockets instead. See dhcp-socket-type described in Section 7.2.4, "Interface Configuration". However, using UDP sockets has certain limitations. In particular, they may not allow for sending responses directly to clients without IPv4 addresses assigned. That's ok, if all your traffic is coming through relay agents. 18.3. Frequently Asked Questions about DHCPv6 18.3.1. Kea DHCPv6 doesn't seem to get incoming traffic. I checked with tcpdump (or other traffic capture software) that the incoming traffic is reaching the box. What's wrong? Please check whether your OS has any IPv6 filtering rules. Many operating systems are shipped with firewalls that discard incoming IPv6 traffic by default. In particular, many Linux distributions do that. Please check the output of the following command: # ip6tables -L -n One common mistake in this area is to use iptables tool, which lists IPv4 firewall rules only. Chapter 19. Acknowledgments Kea is primarily designed, developed, and maintained by Internet Systems Consortium, Inc. It is an open source project and contributions are welcomed. Support for the development of the DHCPv4, DHCPv6 and DHCP-DDNS components was provided by Comcast. Kea was initially implemented as a collection of applications within the BIND 10 framework. Hence, Kea development would not be possible without the generous support of past BIND 10 project sponsors. JPRS and CIRA were Patron Level BIND 10 sponsors. AFNIC, CNNIC, CZ.NIC, DENIC eG, Google, RIPE NCC, Registro.br, .nz Registry Services, and Technical Center of Internet were past BIND 10 sponsors. Afilias, IIS.SE, Nominet, and SIDN were founding sponsors of the BIND 10 project. kea-1.1.0/doc/guide/Makefile.am0000664000175000017500000000447212772445242013112 00000000000000# generated documentation HTMLDOCS = kea-guide.html kea-messages.html DOCS = kea-guide.txt dist_doc_DATA = $(DOCS) dist_html_DATA = $(HTMLDOCS) kea-guide.css kea-logo-100x70.png DOCBOOK = kea-guide.xml intro.xml quickstart.xml install.xml admin.xml config.xml DOCBOOK += keactrl.xml dhcp4-srv.xml dhcp6-srv.xml lease-expiration.xml logging.xml DOCBOOK += ddns.xml hooks.xml libdhcp.xml lfc.xml stats.xml ctrl-channel.xml faq.xml DOCBOOK += classify.xml EXTRA_DIST = $(DOCBOOK) DISTCLEANFILES = $(HTMLDOCS) $(DOCS) kea-messages.xml kea-messages.xml: $(top_srcdir)/tools/system_messages -o $@ \ `find $(top_srcdir) -name "*.mes" -print` # This is not a "man" manual, but reuse this for now for docbook. if GENERATE_DOCS kea-guide.html: $(DOCBOOK) @XSLTPROC@ --novalid --xinclude --nonet \ --path $(top_builddir)/doc \ -o $@ \ --stringparam section.autolabel 1 \ --stringparam section.label.includes.component.label 1 \ --stringparam html.stylesheet kea-guide.css \ http://docbook.sourceforge.net/release/xsl/current/html/docbook.xsl \ $(srcdir)/kea-guide.xml kea-guide.txt: kea-guide.html @ELINKS@ -dump -no-numbering -no-references kea-guide.html > $@ kea-messages.html: kea-messages.xml @XSLTPROC@ --novalid --xinclude --nonet \ --path $(top_builddir)/doc \ -o $@ \ --stringparam generate.toc "book toc" \ --stringparam html.stylesheet kea-guide.css \ http://docbook.sourceforge.net/release/xsl/current/html/docbook.xsl \ kea-messages.xml else $(HTMLDOCS) $(DOCS): @echo Doc generation disabled. Creating dummy $@. Configure with --enable-generate-docs to enable it. @echo Doc generation disabled. Remove this file, configure with --enable-generate-docs, and rebuild Kea > $@ endif if HAVE_DBLATEX CLEANFILES = kea-guide.pdf kea-messages.pdf DBLATEX_FLAGS = --xslt-opts=--path --xslt-opts=$(abs_top_builddir)/doc \ -P doc.collab.show=0 -P latex.output.revhistory=0 \ -P term.breakline=1 -P filename.as.url=0 \ -P imagedata.default.scale="maxwidth=50px,maxheigth=35px" pdf: kea-guide.pdf kea-messages.pdf kea-guide.pdf: $(DOCBOOK) @DBLATEX@ $(DBLATEX_FLAGS) kea-guide.xml kea-messages.pdf: kea-messages.xml @DBLATEX@ $(DBLATEX_FLAGS) kea-messages.xml else pdf kea-guide.pdf kea-messages.pdf: @echo Install dblatex tool and rerun ./configure to be able to generate documentation in PDF format. endif kea-1.1.0/doc/guide/ctrl-channel.xml0000664000175000017500000001615312772445242014151 00000000000000 %version; ]> Management API A classic approach to daemon configuration assumes that the server's configuration is stored in configuration files and, when the configuration is changed, the daemon is restarted. This approach has the significant disadvantage of introducing periods of downtime, when client traffic is not handled. Another risk is that if the new configuration is invalid for whatever reason, the server may refuse to start, which will further extend the downtime period until the issue is resolved. To avoid such problems, both the DHCPv4 and DHCPv6 servers include support for a mechanism that allows on-line reconfiguration without requiring server shutdown. Both servers can be instructed to open control sockets, which is a communication channel. The server is able to receive commands on that channel, act on them and report back status. While the set of commands in Kea 1.1.0 is limited, the number is expected to grow over time. Currently the only supported type of control channel is UNIX stream socket. For details how to configure it, see and . It is likely that support for other control channel types will be added in the future.
Data Syntax Communication over the control channel is conducted using JSON structures. If configured, Kea will open a socket and listen for incoming connections. A process connecting to this socket is expected to send JSON commands structured as follows: { "command": "foo", "arguments": { "param1": "value1", "param2": "value2", ... } } command is the name of command to execute and is mandatory. arguments is a map of parameters required to carry out the given command. The exact content and format of the map is command specific. The server will process the incoming command and then send a response of the form: { "result": 0|1, "text": "textual description", "arguments": { "argument1": "value1", "argument2": "value2", ... } } result indicates the outcome of the command. A value of 0 means success while any non-zero value designates an error. Currently 1 is used as a generic error, but additional error codes may be added in the future. The text field typically appears when result is non-zero and contains a description of the error encountered, but it may also appear for successful results (that is command specific). arguments is a map of additional data values returned by the server which is specific to the command issued. The map is always present, even if it contains no data values.
Using the Control Channel Kea does not currently provide a client for using the control channel. The primary reason for this is the expectation is that the entity using the control channel is typically an IPAM or similar network management/monitoring software which may have quite varied expectations regarding the client and is even likely to be written in languages different than C or C++. Therefore only examples are provided to show how one can take advantage of the API. The easiest way is to use a tool called socat, a tool available from socat homepage, but it is also widely available in Linux and BSD distributions. Once Kea is started, one could connect to the control interface using the following command: $ socat UNIX:/path/to/the/kea/socket - where /path/to/the/kea/socket is the path specified in the Dhcp4/control-socket/socket-name parameter in the Kea configuration file. Text passed to socat will be sent to Kea and the responses received from Kea printed to standard output. It is also easy to open UNIX socket programmatically. An example of such a simplistic client written in C is available in the Kea Developer's Guide, chapter Control Channel Overview, section Using Control Channel.
Commands Supported by Both the DHCPv4 and DHCPv6 Servers
leases-reclaim leases-reclaim command instructs the server to reclaim all expired leases immediately. The command has the following JSON syntax: { "command": "leases-reclaim", "arguments": { "remove": true } } The remove boolean parameter is mandatory and it indicates whether the reclaimed leases should be removed from the lease database (if true), or they should be left in the expired-reclaimed state (if false). The latter facilitates lease affinity, i.e. ability to re-assign expired lease to the same client which used this lease before. See for the details. Also, see for the general information about the processing of expired leases (leases reclamation).
list-commands The list-commands command retrieves a list of all commands supported by the server. It does not take any arguments. An example command may look like this: { "command": "list-commands", "arguments": { } } The server will respond with a list of all supported commands. The arguments element will be a list of strings. Each string will convey one supported command.
shutdown The shutdown command instructs the server to initiate its shutdown procedure. It is the equivalent of sending a SIGTERM signal to the process. This command does not take any arguments. An example command may look like this: { "command": "shutdown", "arguments": { } } The server will respond with a confirmation that the shutdown procedure has been initiated.
kea-1.1.0/doc/guide/admin.xml0000664000175000017500000007061712772445242012674 00000000000000 ]> Kea Database Administration
Databases and Database Version Numbers Kea supports storing leases and host reservations (i.e. static assignments of addresses, prefixes and options) in one of the several supported databases. As future versions of Kea are released, the structure of those databases will change. For example, Kea currently only stores lease information and host reservations. Future versions of Kea will store additional data such as subnet definitions: the database structure will need to be updated to accomdate the extra information. A given version of Kea expects a particular structure in the database and checks for this by examining the version of database it is using. Separate version numbers are maintained for backend databases, independent of the version of Kea itself. It is possible that the backend database version will stay the same through several Kea revisions: similarly, it is possible that the version of backend database may go up several revisions during a Kea upgrade. Versions for each database are independent, so an increment in the MySQL database version does not imply an increment in that of PostgreSQL. Backend versions are specified in a major.minor format. The minor number is increased when there are backward compatible changes introduced. For example, the addition of a new index. It is desirable, but not mandatory to apply such a change; you can run on older database version if you want to. (Although, in the example given, running without the new index may be at the expense of a performance penalty.) On the other hand, the major number is increased when an incompatible change is introduced, for example an extra column is added to a table. If you try to run Kea software on a database that is too old (as signified by mismatched backend major version number), Kea will refuse to run: administrative action will be required to upgrade the database.
The kea-admin Tool To manage the databases, Kea provides the kea-admin tool. It is able to initialize a new database, check its version number, perform a database upgrade, and dump lease data to a text file. kea-admin takes two mandatory parameters: command and backend. Additional, non-mandatory options may be specified. Currently supported commands are: lease-init — Initializes a new lease database. This is useful during a new Kea installation. The database is initialized to the latest version supported by the version of the software being installed. lease-version — Reports the lease database version number. This is not necessarily equal to the Kea version number as each backend has its own versioning scheme. lease-upgrade — Conducts a lease database upgrade. This is useful when upgrading Kea. lease-dump — Dumps the contents of the lease database (for MySQL, PostgreSQL or CQL backends) to a CSV (comma separated values) text file. The first line of the file contains the column names. This is meant to be used as a diagnostic tool, so it provides a portable, human-readable form of the lease data. backend specifies the backend type. Currently supported types are: memfile — Lease information is stored on disk in a text file. mysql — Lease information is stored in a MySQL relational database. pgsql — Lease information is stored in a PostgreSQL relational database. cql — Lease information is stored in a CQL database. Additional parameters may be needed, depending on your setup and specific operation: username, password and database name or the directory where specific files are located. See the appropriate manual page for details (man 8 kea-admin).
Supported Databases The following table presents the capabilities of available backends. Please refer to the specific sections dedicated to each backend to better understand their capabilities and limitations. Choosing the right backend may be essential for success or failure of your deployment. List of available backends Feature Memfile MySQL PostgreSQL CQL(Cassandra) Status Stable Stable Stable Experimental Data format CSV file SQL RMDB SQL RMDB NoSQL database (CQL) Leases yes yes yes yes Host Reservations no yes yes no Options defined on per host basis no yes yes no
memfile The memfile backend is able to store lease information, but is not able to store host reservation details: these must be stored in the configuration file. (There are no plans to add a host reservations storage capability to this backend.) No special initialization steps are necessary for the memfile backend. During the first run, both kea-dhcp4 and kea-dhcp6 will create an empty lease file if one is not present. Necessary disk write permission is required.
Upgrading Memfile Lease Files from an Earlier Version of Kea There are no special steps required to upgrade memfile lease files from an earlier version of Kea to a new version of Kea. During startup the servers will check the schema version of the lease files against their own. If there is a mismatch, the servers will automatically launch the LFC process to convert the files to the server's schema version. While this mechanism is primarily meant to ease the process of upgrading to newer versions of Kea, it can also be used for downgrading should the need arise. When upgrading, any values not present in the original lease files will be assigned appropriate default values. When downgrading, any data present in the files but not in the server's schema will be dropped. If you wish to convert the files manually, prior to starting the servers you may do so by running the LFC process yourself. See for more information.
MySQL MySQL is able to store leases, host reservations and options defined on a per host basis. This section can be safely ignored if you chose to store the data in other backends.
First Time Creation of the MySQL Database If you are setting the MySQL database for the first time, you need to create the database area within MySQL and set up the MySQL user ID under which Kea will access the database. This needs to be done manually: kea-admin is not able to do this for you. To create the database: Log into MySQL as "root": $ mysql -u root -p Enter password: mysql> Create the MySQL database: mysql> CREATE DATABASE database-name; (database-name is the name you have chosen for the database.) Create the user under which Kea will access the database (and give it a password), then grant it access to the database tables: mysql> CREATE USER 'user-name'@'localhost' IDENTIFIED BY 'password'; mysql> GRANT ALL ON database-name.* TO 'user-name'@'localhost'; (user-name and password are the user ID and password you are using to allow Keas access to the MySQL instance. All apostrophes in the command lines above are required.) At this point, you may elect to create the database tables. (Alternatively, you can exit MySQL and create the tables using the kea-admin tool, as explained below.) To do this: mysql> CONNECT database-name; mysql> SOURCE path-to-kea/share/kea/scripts/mysql/dhcpdb_create.mysql (path-to-kea is the location where you installed Kea.) Exit MySQL: mysql> quit Bye $ If you elected not to create the tables in step 4, you can do so now by running the kea-admin tool: $ kea-admin lease-init mysql -u database-user -p database-password -n database-name (Do not do this if you did create the tables in step 4.) kea-admin implements rudimentary checks: it will refuse to initialize a database that contains any existing tables. If you want to start from scratch, you must remove all data manually. (This process is a manual operation on purpose to avoid possibly irretrievable mistakes by kea-admin.)
Upgrading a MySQL Database from an Earlier Version of Kea Sometimes a new Kea version may use newer database schema, so there will be a need to upgrade the existing database. This can be done using the kea-admin lease-upgrade command. To check the current version of the database, use the following command: $ kea-admin lease-version mysql -u database-user -p database-password -n database-name (See for a discussion about versioning.) If the version does not match the minimum required for the new version of Kea (as described in the release notes), the database needs to be upgraded. Before upgrading, please make sure that the database is backed up. The upgrade process does not discard any data but, depending on the nature of the changes, it may be impossible to subsequently downgrade to an earlier version. To perform an upgrade, issue the following command: $ kea-admin lease-upgrade mysql -u database-user -p database-password -n database-name
PostgreSQL A PostgreSQL database must be set up if you want Kea to store lease and other information in PostgreSQL. This step can be safely ignored if you are using other database backends.
First Time Creation of the PostgreSQL Database The first task is to create both the lease database and the user under which the servers will access it. A number of steps are required: Log into PostgreSQL as "root": $ sudo -u postgres psql postgres Enter password: postgres=# Create the database: postgres=# CREATE DATABASE database-name; CREATE DATABASE postgres=# (database-name is the name you have chosen for the database.) Create the user under which Kea will access the database (and give it a password), then grant it access to the database: postgres=# CREATE USER user-name WITH PASSWORD 'password'; CREATE ROLE postgres=# GRANT ALL PRIVILEGES ON DATABASE database-name TO user-name; GRANT postgres=# Exit PostgreSQL: postgres=# \q Bye $ At this point you are ready to create the database tables. This can be done using the kea-admin tool as explained in the next section (recommended), or manually. To create the tables manually enter the following command. Note that PostgreSQL will prompt you to enter the new user's password you specified in Step 3. When the command completes you will be returned to the shell prompt. You should see output similar to following: $ psql -d database-name -U user-name -f path-to-kea/share/kea/scripts/pgsql/dhcpdb_create.pgsql Password for user user-name: CREATE TABLE CREATE INDEX CREATE INDEX CREATE TABLE CREATE INDEX CREATE TABLE START TRANSACTION INSERT 0 1 INSERT 0 1 INSERT 0 1 COMMIT CREATE TABLE START TRANSACTION INSERT 0 1 COMMIT $ (path-to-kea is the location where you installed Kea.) If instead you encounter an error like: psql: FATAL: no pg_hba.conf entry for host "[local]", user "user-name", database "database-name", SSL off ... you will need to alter the PostgreSQL configuration. Kea uses password authentication when connecting to the database and must have the appropriate entries added to PostgreSQL's pg_hba.conf file. This file is normally located in the primary data directory for your PostgreSQL server. The precise path may vary but the default location for PostgreSQL 9.3 on Centos 6.5 is: /var/lib/pgsql/9.3/data/pg_hba.conf. Assuming Kea is running on the same host as PostgreSQL, adding lines similar to following should be sufficient to provide password-authenticated access to Kea's database: local database-name user-name password host database-name user-name 127.0.0.1/32 password host database-name user-name ::1/128 password These edits are primarily intended as a starting point not a definitive reference on PostgreSQL administration or database security. Please consult your PostgreSQL user manual before making these changes as they may expose other databases that you run. It may be necessary to restart PostgreSQL in order for these changes to take effect.
Initialize the PostgreSQL Database Using kea-admin If you elected not to create the tables manually, you can do so now by running the kea-admin tool: $ kea-admin lease-init pgsql -u database-user -p database-password -n database-name Do not do this if you already created the tables in manually. kea-admin implements rudimentary checks: it will refuse to initialize a database that contains any existing tables. If you want to start from scratch, you must remove all data manually. (This process is a manual operation on purpose to avoid possibly irretrievable mistakes by kea-admin.)
Upgrading a PostgreSQL Database from an Earlier Version of Kea The PostgreSQL database schema can be upgraded using the same tool and commands as described in , with the exception that the "pgsql" database backend type must be used in the commands. Use the following command to check the current schema version: $ kea-admin lease-version pgsql -u database-user -p database-password -n database-name Use the following command to perform an upgrade: $ kea-admin lease-upgrade pgsql -u database-user -p database-password -n database-name
CQL (Cassandra) Cassandra, or Cassandra Query Language (CQL), is the newest backend added to Kea. Since it was added recently and has not undergone as much testing as other backends, it is considered experimental: please use with caution. The CQL backend is currently able to store leases only. The ability to store host reservations will likely be added some time in the future. The CQL database must be properly set up if you want Kea to store information in CQL. This section can be safely ignored if you chose to store the data in other backends.
First Time Creation of the Cassandra Database If you are setting up the CQL database for the first time, you need to create the keyspace area within CQL. This needs to be done manually: kea-admin is not able to do this for you. To create the database: Export CQLSH_HOST environemnt variable: $ export CQLSH_HOST=localhost Log into CQL: $ cqlsh cql> Create the CQL keyspace: cql> CREATE KEYSPACE keyspace-name WITH replication = {'class' : 'SimpleStrategy','replication_factor' : 1}; (keyspace-name is the name you have chosen for the keyspace) At this point, you may elect to create the database tables. (Alternatively, you can exit CQL and create the tables using the kea-admin tool, as explained below) To do this: cqslh -k keyspace-name -f path-to-kea/share/kea/scripts/cql/dhcpdb_create.cql (path-to-kea is the location where you installed Kea) If you elected not to create the tables in step 4, you can do so now by running the kea-admin tool: $ kea-admin lease-init cql -n database-name (Do not do this if you did create the tables in step 4.) kea-admin implements rudimentary checks: it will refuse to initialize a database that contains any existing tables. If you want to start from scratch, you must remove all data manually. (This process is a manual operation on purpose to avoid possibly irretrievable mistakes by kea-admin)
Upgrading a CQL Database from an Earlier Version of Kea Sometimes a new Kea version may use newer database schema, so there will be a need to upgrade the existing database. This can be done using the kea-admin lease-upgrade command. To check the current version of the database, use the following command: $ kea-admin lease-version cql -n database-name (See for a discussion about versioning) If the version does not match the minimum required for the new version of Kea (as described in the release notes), the database needs to be upgraded. Before upgrading, please make sure that the database is backed up. The upgrade process does not discard any data but, depending on the nature of the changes, it may be impossible to subsequently downgrade to an earlier version. To perform an upgrade, issue the following command: $ kea-admin lease-upgrade cql -n database-name
Using Read-Only Databases with Host Reservations If a read-only database is used for storing host reservations, Kea must be explicitly configured to operate on the database in read-only mode. Sections and describe when such configuration may be reqired and how to configure Kea to operate using a read-only host database.
Limitations Related to the use of SQL Databases The lease expiration time is stored in the SQL database for each lease as a timestamp value. Kea developers observed that MySQL database doesn't accept timestamps beyond 2147483647 seconds (maximum signed 32-bit number) from the beginning of the epoch. At the same time, some versions of PostgreSQL do accept greater values but the value is altered when it is read back. For this reason the lease database backends put the restriction for the maximum timestamp to be stored in the database, which is equal to the maximum signed 32-bit number. This effectively means that the current Kea version can't store the leases which expiration time is later than 2147483647 seconds since the beginning of the epoch (around year 2038). This will be fixed when the database support for longer timestamps is available.
kea-1.1.0/doc/guide/logging.xml0000664000175000017500000010513512772445242013224 00000000000000 ]> Logging
Logging Configuration During its operation Kea may produce many messages. They differ in severity (some are more important than others) and source (some are produced by specific components, e.g. hooks). It is useful to understand which log messages are needed and which are not, and configure your logging appropriately. For example, debug level messages can be safely ignored in a typical deployment. They are, however, very useful when debugging a problem. The logging system in Kea is configured through the Logging section in your configuration file. All daemons (e.g. DHCPv4 and DHCPv6 servers) will use the configuration in the Logging section to see what should be logged and to where. This allows for sharing identical logging configuration between daemons.
Loggers Within Kea, a message is logged through an entity called a "logger". Different components log messages through different loggers, and each logger can be configured independently of one another. Some components, in particular the DHCP server processes, may use multiple loggers to log messages pertaining to different logical functions of the component. For example, the DHCPv4 server uses one logger for messages pertaining to packet reception and transmission, another logger for messages related to lease allocation and so on. Some of the libraries used by the Kea servers, e.g. libdhcpsrv, use their own loggers. Users implementing hooks libraries (code attached to the server at runtime) are responsible for creating the loggers used by those libraries. Such loggers should have unique names, different from the logger names used by Kea. In this way the messages output by the hooks library can be distingued from messages issued by the core Kea code. Unique names also allow the loggers to be configured independently of loggers used by Kea. Whenever it makes sense, a hook library can use multiple loggers to log messages pertaining to different logical parts of the library. In the Logging section of a configuration file you can specify the configuration for zero or more loggers (including loggers used by the proprietary hooks libraries). If there are no loggers specified, the code will use default values: these cause Kea to log messages of INFO severity or greater to standard output. There is also a small time window after Kea has been started, but has not yet read its configuration. Logging in this short period can be controlled using environment variables. For details, see . The three main elements of a logger configuration are: name (the component that is generating the messages), the severity (what to log), and the output_commands (where to log). There is also a debuglevel element, which is only relevant if debug-level logging has been selected.
name (string) Each logger in the system has a name, the name being that of the component binary file using it to log messages. For instance, if you want to configure logging for the DHCPv4 server, you add an entry for a logger named kea-dhcp4. This configuration will then be used by the loggers in the DHCPv4 server, and all the libraries used by it (unless a library defines its own logger and there is specific logger configuration that applies to that logger). When tracking down an issue with the server's operation, use of DEBUG logging is required to obtain the verbose output needed for problems diagnosis. However, the high verbosity is likely to overwhelm the logging system in cases when the server is processing high volume traffic. To mitigate this problem, use can be made of the fact that Kea uses multiple loggers for different functional parts of the server and that each of these can be configured independently. If the user is reasonably confident that a problem originates in a specific function of the server, or that the problem is related to the specific type of operation, they may enable high verbosity only for the relevant logger, so limiting the debug messages to the required minimum. The loggers are associated with a particular library or binary of Kea. However, each library or binary may (and usually does) include multiple loggers. For example, the DHCPv4 server binary contains separate loggers for: packet parsing, for dropped packets, for callouts etc. The loggers form a hierarchy. For each program in Kea, there is a "root" logger, named after the program (e.g. the root logger for kea-dhcp (the DHCPv4 server) is named kea-dhcp4. All other loggers are children of this logger, and are named accordingly, e.g. the the allocation engine in the DHCPv4 server logs messages using a logger called kea-dhcp4.alloc-engine. This relationship is important as each child logger derives its default configuration from its parent root logger. In the typical case, the root logger configuration is the only logging configuration specified in the configuration file and so applies to all loggers. If an entry is made for a given logger, any attributes specified override those of the root logger, whereas any not specified are inherited from it. To illustrate this, suppose you are using the DHCPv4 server with the root logger kea-dhcp4 logging at the INFO level. In order to enable DEBUG verbosity for the DHCPv4 packet drops, you must create configuration entry for the logger called kea-dhcp4.bad-packets and specify severity DEBUG for this logger. All other configuration parameters may be omited for this logger if the logger should use the default values specified in the root logger's configuration. If there are multiple logger specifications in the configuration that might match a particular logger, the specification with the more specific logger name takes precedence. For example, if there are entries for both kea-dhcp4 and kea-dhcp4.dhcpsrv, the DHCPv4 server — and all libraries it uses that are not dhcpsrv — will log messages according to the configuration in the first entry (kea-dhcp4). Currently defined loggers are: kea-dhcp4 - the root logger for the DHCPv4 server. All components used by the DHCPv4 server inherit the settings from this logger. kea-dhcp4.alloc-engine - used by the lease allocation engine, which is responsible for managing leases in the lease database, i.e. create, modify and remove DHCPv4 leases as a result of processing messages from the clients. kea-dhcp4.bad-packets - used by the DHCPv4 server daemon for logging inbound client packets that were dropped or to which the server responded with a DHCPNAK. It allows administrators to configure a separate log output that contains only packet drop and reject entries. kea-dhcp4.callouts - used to log messages pertaining to the callouts registration and execution for the particular hook point. kea-dhcp4.commands - used to log messages relating to the handling of commands received by the the DHCPv4 server over the command channel. kea-dhcp4.ddns - used by the DHCPv4 server to log messages related to the Client FQDN and Hostname option processing. It also includes log messages related to the relevant DNS updates. kea-dhcp4.dhcp4 - used by the DHCPv4 server daemon to log basic operations. kea-dhcp4.dhcpsrv - the base logger for the libdhcpsrv library. kea-dhcp4.eval - used to log messages relating to the client classification expression evaluation code. kea-dhcp4.hooks - used to log messages related to management of hooks libraries, e.g. registration and deregistration of the libraries, and to the initialization of the callouts execution for various hook points within the DHCPv4 server. kea-dhcp4.hosts - used within the libdhcpsrv and it logs messages related to the management of the DHCPv4 host reservations, i.e. retrieval of the reservations and adding new reservations. kea-dhcp4.leases - used by the DHCPv4 server to log messages related to the lease allocation. The messages include detailed information about the allocated or offered leases, errors during the lease allocation etc. kea-dhcp4.options - used by the DHCPv4 server to log messages related to processing of the options in the DHCPv4 messages, i.e. parsing options, encoding options into on-wire format and packet classification using options contained in the received packets. kea-dhcp4.packets - this logger is mostly used to log messages related to transmission of the DHCPv4 packets, i.e. packet reception and sending a response. Such messages include information about the source and destination IP addresses and interfaces used to transmit packets. The logger is also used to log messages related to subnet selection, as this selection is usually based on the IP addresses and/or interface names, which can be retrieved from the received packet, even before the DHCPv4 message carried in the packet is parsed. kea-dhcp6 - the root logger for the DHCPv6 server. All components used by the DHCPv6 server inherit the settings from this logger if there is no specialized logger provided. kea-dhcp6.alloc-engine - used used by the lease allocation engine, which is responsible for managing leases in the lease database, i.e. create, modify and remove DHCPv6 leases as a result of processing messages from the clients. kea-dhcp6.bad-packets - used used by the DHCPv6 server daemon for logging inbound client packets that were dropped. kea-dhcp6.callouts - used to log messages pertaining to the callouts registration and execution for the particular hook point. kea-dhcp6.commands - used to log messages relating to the handling of commands received by the the DHCPv6 server over the command channel. kea-dhcp6.ddns - this logger is used by the DHCPv6 server to log messages related to the Client FQDN option processing. It also includes log messages related to the relevant DNS updates. kea-dhcp6.dhcp6 - used DHCPv6 server daemon to log basic operations. kea-dhcp6.dhcpsrv - the base logger for the libdhcpsrv library. kea-dhcp6.eval - used to log messages relating to the client classification expression evaluation code. kea-dhcp6.hooks - this logger is used to log messages related to management of hooks libraries, e.g. registration and deregistration of the libraries, and to the initialization of the callouts execution for various hook points within the DHCPv6 server. kea-dhcp6.hosts - used within the libdhcpsrv and it logs messages related to the management of the DHCPv6 host reservations, i.e. retrieval of the reservations and adding new reservations. kea-dhcp6.leases - used by the DHCPv6 server to log messages related to the lease allocation. The messages include detailed information about the allocated or offered leases, errors during the lease allocation etc. kea-dhcp6.options - used by the DHCPv6 server to log messages related to processing of the options in the DHCPv6 messages, i.e. parsing options, encoding options into on-wire format and packet classification using options contained in the received packets. kea-dhcp6.packets - this logger is mostly used to log messages related to transmission of the DHCPv6 packets, i.e. packet reception and sending a response. Such messages include the information about the source and destination IP addresses and interfaces used to transmit packets. This logger is also used to log messages related to subnet selection, as this selection is usually based on the IP addresses and/or interface names, which can be retrieved from the received packet, even before the DHCPv6 message carried in the packet is parsed. kea-dhcp-ddns - the root logger for the kea-dhcp-ddns daemon. All components used by this daemon inherit the settings from this logger if there is no specialized logger provided. kea-dhcp-ddns.dhcpddns - the logger used by the kea-dhcp-ddns daemon for logging configuration and global event information. This logger does not specify logging settings for libraries used by the daemon. kea-dhcp-ddns.dhcp-to-d2 - used by the kea-dhcp-ddns daemon for logging information about events dealing with receiving messages from the DHCP servers and adding them to the queue for processing. kea-dhcp-ddns.d2-to-dns - used by the kea-dhcp-ddns daemon for logging information about events dealing with sending and receiving messages with the DNS servers. Note that user-defined hook libraries should not use any of those loggers but should define new loggers with names that correspond to the libraries using them. Suppose that the user created the library called libpacket-capture to dump packets received and transmitted by the server to the file. The appropriate name for the logger could be kea-dhcp4.packet-capture. (Note that the hook library implementor only specifies the second part of this name, i.e. packet-capture. The first part is a root logger name and is prepended by the Kea logging system.) It is also important to note that since this new logger is a child of a root logger, it inherits the configuration from the root logger, something that can be overridden by an entry in the configuration file. The list of loggers above excludes any loggers implemented in hooks libraries. Please consult the documentation for the libraries for the names of the loggers they define. Additional loggers may be defined in future versions of Kea. The easiest way to find out the logger name is to configure all logging to go to a single destination and look for specific logger names. See for details.
severity (string) This specifies the category of messages logged. Each message is logged with an associated severity which may be one of the following (in descending order of severity): FATAL - associated with messages generated by a condition that is so serious that the server cannot continue executing. ERROR- associated with messages generated by an error condition. The server will continue executing, but the results may not be as expected. WARN - indicates an out of the ordinary condition. However, the server will continue executing normally. INFO - an informational message marking some event. DEBUG - messages produced for debugging purposes. When the severity of a logger is set to one of these values, it will only log messages of that severity and above (e.g. setting the logging severity to INFO will log INFO, WARN, ERROR and FATAL messages). The severity may also be set to NONE, in which case all messages from that logger are inhibited. The keactrl tool, described in , can be configured to start the servers in the verbose mode. If this is the case, the settings of the logging severity in the configuration file will have no effect, i.e. the servers will use logging severity of DEBUG regardless of the logging settings specified in the configuration file. If you need to control severity via configuration file, please make sure that the kea_verbose value is set to "no" within the keactrl configuration.
debuglevel (integer) When a logger's severity is set to DEBUG, this value specifies what level of debug messages should be printed. It ranges from 0 (least verbose) to 99 (most verbose). If severity for the logger is not DEBUG, this value is ignored.
output_options (list) Each logger can have zero or more . These specify where log messages are sent. These are explained in detail below.
output (string) This value determines the type of output. There are several special values allowed here: stdout (messages are printed on standard output), stderr (messages are printed on stderr), syslog (messages are logged to syslog using default name, syslog:name (messages are logged to syslog using specified name). Any other value is interpreted as a filename to which messages should be written.
flush (true of false) Flush buffers after each log message. Doing this will reduce performance but will ensure that if the program terminates abnormally, all messages up to the point of termination are output. The default is "true".
maxsize (integer) Only relevant when destination is file, this is maximum file size of output files in bytes. When the maximum size is reached, the file is renamed and a new file opened. (For example, a ".1" is appended to the name — if a ".1" file exists, it is renamed ".2", etc.) If this is set to 0 or omitted, no maximum file size is used. Due to a limitation of the underlying logging library (log4cplus), rolling over the log files (from ".1" to ".2", etc) may show odd results: There can be multiple small files at the timing of roll over. This can happen when multiple processes try to roll over the files simultaneously. Version 1.1.0 of log4cplus solved this problem, so if this version or later of log4cplus is used to build Kea, it should not happen. Even for older versions it is normally expected to happen rarely unless the log messages are produced very frequently by multiple different processes.
maxver (integer) Maximum number of old log files to keep around when rolling the output file. Only relevant when is file.
Example Logger Configurations In this example we want to set the global logging to write to the console using standard output. "Logging": { "loggers": [ { "name": "kea-dhcp4", "output_options": [ { "output": "stdout" } ], "severity": "WARN" } ] } In this second example, we want to store debug log messages in a file that is at most 2MB and keep up to 8 copies of old logfiles. Once the logfile grows to 2MB, it will be renamed and a new file file be created. "Logging": { "loggers": [ { "name": "kea-dhcp6", "output_options": [ { "output": "/var/log/kea-debug.log", "maxver": 8, "maxsize": 204800, "flush": true } ], "severity": "DEBUG", "debuglevel": 99 } ] }
Logging Message Format Each message written to the configured logging destinations comprises a number of components that identify the origin of the message and, if the message indicates a problem, information about the problem that may be useful in fixing it. Consider the message below logged to a file: 2014-04-11 12:58:01.005 INFO [kea-dhcp4.dhcpsrv/27456] DHCPSRV_MEMFILE_DB opening memory file lease database: type=memfile universe=4 Note: the layout of messages written to the system logging file (syslog) may be slightly different. This message has been split across two lines here for display reasons; in the logging file, it will appear on one line. The log message comprises a number of components: 2014-04-11 12:58:01.005 The date and time at which the message was generated. INFO The severity of the message. [kea-dhcp4.dhcpsrv/27456] The source of the message. This comprises two elements: the Kea process generating the message (in this case, kea-dhcp4) and the component within the program from which the message originated (dhcpsrv, which is the name of the common library used by DHCP server implementations). The number after the slash is a process id (pid). DHCPSRV_MEMFILE_DB The message identification. Every message in Kea has a unique identification, which can be used as an index into the Kea Messages Manual () from which more information can be obtained. opening memory file lease database: type=memfile universe=4 A brief description. Within this text, information relating to the condition that caused the message to be logged will be included. In this example, the information is logged that the in-memory lease database backend will be used to store DHCP leases.
Logging During Kea Startup The logging configuration is specified in the configuration file. However, when Kea starts, the file is not read until some way into the initialization process. Prior to that, the logging settings are set to default values, although it is possible to modify some aspects of the settings by means of environment variables. Note that in the absence of any logging configuration in the configuration file, the settings of (possibly modified) default configuration will persist while the program is running. The following environment variables can be used to control the behavior of logging during startup: KEA_LOCKFILE_DIR Specifies a directory where the logging system should create its lock file. If not specified, it is prefix/var/run/kea, where prefix defaults to /usr/local. This variable must not end with a slash. There is one special value: "none", which instructs Kea to not create lock file at all. This may cause issues if several processes log to the same file. KEA_LOGGER_DESTINATION Specifies logging output. There are several special values. stdout Log to standard output. stderr Log to standard error. syslog:fac Log via syslog. The optional fac (which is separated from the word "syslog" by a colon) specifies the facility to be used for the log messages. Unless specified, messages will be logged using the facility "local0". Any other value is treated as a name of the output file. If not specified otherwise, Kea will log to standard output.
kea-1.1.0/doc/guide/dhcp6-srv.xml0000664000175000017500000052016012772445242013411 00000000000000 ]> The DHCPv6 Server
Starting and Stopping the DHCPv6 Server It is recommended that the Kea DHCPv6 server be started and stopped using keactrl (described in ). However, it is also possible to run the server directly: it accepts the following command-line switches: -c file - specifies the configuration file. This is the only mandatory switch. -d - specifies whether the server logging should be switched to verbose mode. In verbose mode, the logging severity and debuglevel specified in the configuration file are ignored and "debug" severity and the maximum debuglevel (99) are assumed. The flag is convenient, for temporarily switching the server into maximum verbosity, e.g. when debugging. -p port - specifies UDP port on which the server will listen. This is only useful during testing, as a DHCPv6 server listening on ports other than the standard ones will not be able to handle regular DHCPv6 queries. -v - prints out the Kea version and exits. -V - prints out the Kea extended version with additional parameters and exits. The listing includes the versions of the libraries dynamically linked to Kea. -W - prints out the Kea configuration report and exits. The report is a copy of the config.report file produced by ./configure: it is embedded in the executable binary. The config.report may also be accessed more directly. The following command may be used to extract this information. The binary path may be found in the install directory or in the .libs subdirectory in the source tree. For example kea/src/bin/dhcp6/.libs/kea-dhcp6. strings path/kea-dhcp6 | sed -n 's/;;;; //p' On start-up, the server will detect available network interfaces and will attempt to open UDP sockets on all interfaces mentioned in the configuration file. Since the DHCPv6 server opens privileged ports, it requires root access. Make sure you run this daemon as root. During startup the server will attempt to create a PID file of the form: localstatedir]/[conf name].kea-dhcp6.pid where: localstatedir: The value as passed into the build configure script. It defaults to "/usr/local/var". Note that this value may be overridden at run time by setting the environment variable KEA_PIDFILE_DIR. This is intended primarily for testing purposes. conf name: The configuration file name used to start the server, minus all preceding path and file extension. For example, given a pathname of "/usr/local/etc/kea/myconf.txt", the portion used would be "myconf". If the file already exists and contains the PID of a live process, the server will issue a DHCP6_ALREADY_RUNNING log message and exit. It is possible, though unlikely, that the file is a remnant of a system crash and the process to which the PID belongs is unrelated to Kea. In such a case it would be necessary to manually delete the PID file. The server can be stopped using the kill command. When running in a console, the server can be shut down by pressing ctrl-c. It detects the key combination and shuts down gracefully.
DHCPv6 Server Configuration
Introduction This section explains how to configure the DHCPv6 server using the Kea configuration backend. (Kea configuration using any other backends is outside of scope of this document.) Before DHCPv6 is started, its configuration file has to be created. The basic configuration is as follows: { # DHCPv6 configuration starts on the next line "Dhcp6": { # First we set up global values "valid-lifetime": 4000, "renew-timer": 1000, "rebind-timer": 2000, "preferred-lifetime": 3000, # Next we setup the interfaces to be used by the server. "interfaces-config": { "interfaces": [ "eth0" ] }, # And we specify the type of lease database "lease-database": { "type": "memfile", "persist": true, "name": "/var/kea/dhcp6.leases" }, # Finally, we list the subnets from which we will be leasing addresses. "subnet6": [ { "subnet": "2001:db8:1::/64", "pools": [ { "pool": "2001:db8:1::1-2001:db8:1::ffff" } ] } ] # DHCPv6 configuration ends with the next line } } The following paragraphs provide a brief overview of the parameters in the above example together with their format. Subsequent sections of this chapter go into much greater detail for these and other parameters. The lines starting with a hash (#) are comments and are ignored by the server; they do not impact its operation in any way. The configuration starts in the first line with the initial opening curly bracket (or brace). Each configuration consists of one or more objects. In this specific example, we have only one object, called Dhcp6. This is a simplified configuration, as usually there will be additional objects, like Logging or DhcpDns, but we omit them now for clarity. The Dhcp6 configuration starts with the "Dhcp6": { line and ends with the corresponding closing brace (in the above example, the brace after the last comment). Everything defined between those lines is considered to be the Dhcp6 configuration. In the general case, the order in which those parameters appear does not matter. There are two caveats here though. The first one is to remember that the configuration file must be well formed JSON. That means that parameters for any given scope must be separated by a comma and there must not be a comma after the last parameter. When reordering a configuration file, keep in mind that moving a parameter to or from the last position in a given scope may also require moving the comma. The second caveat is that it is uncommon — although legal JSON — to repeat the same parameter multiple times. If that happens, the last occurrence of a given parameter in a given scope is used while all previous instances are ignored. This is unlikely to cause any confusion as there are no real life reasons to keep multiple copies of the same parameter in your configuration file. Moving onto the DHCPv6 configuration elements, the very first few elements define some global parameters. valid-lifetime defines for how long the addresses (leases) given out by the server are valid. If nothing changes, a client that got an address is allowed to use it for 4000 seconds. (Note that integer numbers are specified as is, without any quotes around them.) The address will become deprecated in 3000 seconds (clients are allowed to keep old connections, but can't use this address for creating new connections). renew-timer and rebind-timer are values that define T1 and T2 timers that govern when the client will begin the renewal and rebind procedures. The interfaces-config map specifies the server configuration concerning the network interfaces, on which the server should listen to the DHCP messages. The interfaces parameter specifies a list of network interfaces on which the server should listen. Lists are opened and closed with square brackets, with elements separated by commas. Had we wanted to listen on two interfaces, the interfaces-config would look like this: "interfaces-config": { "interfaces": [ "eth0", "eth1" ] }, The next couple of lines define the lease database, the place where the server stores its lease information. This particular example tells the server to use memfile, which is the simplest (and fastest) database backend. It uses an in-memory database and stores leases on disk in a CSV file. This is a very simple configuration. Usually the lease database configuration is more extensive and contains additional parameters. Note that lease-database is an object and opens up a new scope, using an opening brace. Its parameters (just one in this example - type) follow. Had there been more than one, they would be separated by commas. This scope is closed with a closing brace. As more parameters for the Dhcp6 definition follow, a trailing comma is present. Finally, we need to define a list of IPv6 subnets. This is the most important DHCPv6 configuration structure as the server uses that information to process clients' requests. It defines all subnets from which the server is expected to receive DHCP requests. The subnets are specified with the subnet6 parameter. It is a list, so it starts and ends with square brackets. Each subnet definition in the list has several attributes associated with it, so it is a structure and is opened and closed with braces. At minimum, a subnet definition has to have at least two parameters: subnet (that defines the whole subnet) and pools (which is a list of dynamically allocated pools that are governed by the DHCP server). The example contains a single subnet. Had more than one been defined, additional elements in the subnet6 parameter would be specified and separated by commas. For example, to define two subnets, the following syntax would be used: "subnet6": [ { "pools": [ { "pool": "2001:db8:1::/112" } ], "subnet": "2001:db8:1::/64" }, { "pools": [ { "pool": "2001:db8:2::1-2001:db8:2::ffff" } ], "subnet": "2001:db8:2::/64" } ] Note that indentation is optional and is used for aesthetic purposes only. In some cases in may be preferable to use more compact notation. After all parameters are specified, we have two contexts open: global and Dhcp6, hence we need two closing curly brackets to close them. In a real life configuration file there most likely would be additional components defined such as Logging or DhcpDdns, so the closing brace would be followed by a comma and another object definition.
Lease Storage All leases issued by the server are stored in the lease database. Currently there are four database backends available: memfile (which is the default backend), MySQL, PostgreSQL and Cassandra.
Memfile - Basic Storage for Leases The server is able to store lease data in different repositories. Larger deployments may elect to store leases in a database. describes this option. In typical smaller deployments though, the server will store lease information in a CSV file rather than a database. As well as requiring less administration, an advantage of using a file for storage is that it eliminates a dependency on third-party database software. The configuration of the file backend (Memfile) is controlled through the Dhcp6/lease-database parameters. The type parameter is mandatory and it specifies which storage for leases the server should use. The value of "memfile" indicates that the file should be used as the storage. The following list gives additional, optional, parameters that can be used to configure the Memfile backend. persist: controls whether the new leases and updates to existing leases are written to the file. It is strongly recommended that the value of this parameter is set to true at all times, during the server's normal operation. Not writing leases to disk will mean that if a server is restarted (e.g. after a power failure), it will not know what addresses have been assigned. As a result, it may hand out addresses to new clients that are already in use. The value of false is mostly useful for performance testing purposes. The default value of the persist parameter is true, which enables writing lease updates to the lease file. name: specifies an absolute location of the lease file in which new leases and lease updates will be recorded. The default value for this parameter is "[kea-install-dir]/var/kea/kea-leases6.csv" . lfc-interval: specifies the interval in seconds, at which the server will perform a lease file cleanup (LFC). This removes redundant (historical) information from the lease file and effectively reduces the lease file size. The cleanup process is described in more detailed fashion further in this section. The default value of the lfc-interval is 0, which disables the LFC. An example configuration of the Memfile backend is presented below: "Dhcp6": { "lease-database": { "type": "memfile", "persist": true, "name": "/tmp/kea-leases6.csv", "lfc-interval": 1800 } } This configuration selects the /tmp/kea-leases6.csv as the storage for lease information and enables persistence (writing lease updates to this file). It also configures the backend perform the periodic cleanup of the lease files, executed every 30 minutes. It is important to know how the lease file contents are organized to understand why the periodic lease file cleanup is needed. Every time the server updates a lease or creates a new lease for the client, the new lease information must be recorded in the lease file. For performance reasons, the server does not update the existing client's lease in the file, as it would potentially require rewriting the entire file. Instead, it simply appends the new lease information to the end of the file: the previous lease entries for the client are not removed. When the server loads leases from the lease file, e.g. at the server startup, it assumes that the latest lease entry for the client is the valid one. The previous entries are discarded. This means that the server can re-construct the accurate information about the leases even though there may be many lease entries for each client. However, storing many entries for each client results in bloated lease file and impairs the performance of the server's startup and reconfiguration as it needs to process a larger number of lease entries. Lease file cleanup (LFC) removes all previous entries for each client and leaves only the latest ones. The interval at which the cleanup is performed is configurable, and it should be selected according to the frequency of lease renewals initiated by the clients. The more frequent the renewals, the smaller the value of lfc-interval should be. Note however, that the LFC takes time and thus it is possible (although unlikely) that new cleanup is started while the previous cleanup instance is still running, if the lfc-interval is too short. The server would recover from this by skipping the new cleanup when it detects that the previous cleanup is still in progress. But it implies that the actual cleanups will be triggered more rarely than configured. Moreover, triggering a new cleanup adds an overhead to the server which will not be able to respond to new requests for a short period of time when the new cleanup process is spawned. Therefore, it is recommended that the lfc-interval value is selected in a way that would allow for the LFC to complete the cleanup before a new cleanup is triggered. Lease file cleanup is performed by a separate process (in background) to avoid a performance impact on the server process. In order to avoid the conflicts between two processes both using the same lease files, the LFC process operates on the copy of the original lease file, rather than on the lease file used by the server to record lease updates. There are also other files being created as a side effect of the lease file cleanup. The detailed description of the LFC is located on the Kea wiki: .
Lease Database Configuration Lease database access information must be configured for the DHCPv6 server, even if it has already been configured for the DHCPv4 server. The servers store their information independently, so each server can use a separate database or both servers can use the same database. Lease database configuration is controlled through the Dhcp6/lease-database parameters. The type of the database must be set to "memfile", "mysql", "postgresql" or "cql", e.g. "Dhcp6": { "lease-database": { "type": "mysql", ... }, ... } Next, the name of the database is to hold the leases must be set: this is the name used when the database was created (see , or ). "Dhcp6": { "lease-database": { "name": "database-name" , ... }, ... } If the database is located on a different system to the DHCPv6 server, the database host name must also be specified. (It should be noted that this configuration may have a severe impact on server performance.): "Dhcp6": { "lease-database": { "host": remote-host-name, ... }, ... } The usual state of affairs will be to have the database on the same machine as the DHCPv6 server. In this case, set the value to the empty string: "Dhcp6": { "lease-database": { "host" : "", ... }, ... } Should the database be located on a different system, you may need to specify a longer interval for the connection timeout: "Dhcp6": { "lease-database": { "connect-timeout" : timeout-in-seconds, ... }, ... } The default value of five seconds should be more than adequate for local connections. If a timeout is given though, it should be an integer greater than zero. Finally, the credentials of the account under which the server will access the database should be set: "Dhcp6": { "lease-database": { "user": "user-name", "password": "password", ... }, ... } If there is no password to the account, set the password to the empty string "". (This is also the default.)
Hosts Storage Kea is also able to store information about host reservations in the database. The hosts database configuration uses the same syntax as the lease database. In fact, a Kea server opens independent connections for each purpose, be it lease or hosts information. This arrangement gives the most flexibility. Kea can be used to keep leases and host reservations separately, but can also point to the same database. Currently the supported hosts database types are MySQL and PostgreSQL. The Cassandra backend does not support host reservations yet. Please note that usage of hosts storage is optional. A user can define all host reservations in the configuration file. That is the recommended way if the number of reservations is small. However, when the number of reservations grows it's more convenient to use host storage. Please note that both storage methods (configuration file and one of the supported databases) can be used together. If hosts are defined in both places, the definitions from the configuration file are checked first and external storage is checked later, if necessary.
DHCPv6 Hosts Database Configuration Hosts database configuration is controlled through the Dhcp6/hosts-database parameters. If enabled, the type of the database must be set to "mysql" or "postgresql". Other hosts backends may be added in later version of Kea. "Dhcp6": { "hosts-database": { "type": "mysql", ... }, ... } Next, the name of the database to hold the reservations must be set: this is the name used when the database was created (see for instructions how to setup desired database type). "Dhcp6": { "hosts-database": { "name": "database-name" , ... }, ... } If the database is located on a different system than the DHCPv6 server, the database host name must also be specified. (Again it should be noted that this configuration may have a severe impact on server performance): "Dhcp6": { "hosts-database": { "host": remote-host-name, ... }, ... } The usual state of affairs will be to have the database on the same machine as the DHCPv6 server. In this case, set the value to the empty string: "Dhcp6": { "hosts-database": { "host" : "", ... }, ... } Finally, the credentials of the account under which the server will access the database should be set: "Dhcp6": { "hosts-database": { "user": "user-name", "password": "password", ... }, ... } If there is no password to the account, set the password to the empty string "". (This is also the default.)
Using Read-Only Databases for Host Reservations In some deployments the database user whose name is specified in the database backend configuration may not have write privileges to the database. This is often required by the policy within a given network to secure the data from being unintentionally modified. In many cases administrators have inventory databases deployed, which contain substantially more information about the hosts than static reservations assigned to them. The inventory database can be used to create a view of a Kea hosts database and such view is often read only. Kea host database backends operate with an implicit configuration to both read from and write to the database. If the database user does not have write access to the host database, the backend will fail to start and the server will refuse to start (or reconfigure). However, if access to a read only host database is required for retrieving reservations for clients and/or assign specific addresses and options, it is possible to explicitly configure Kea to start in "read-only" mode. This is controlled by the readonly boolean parameter as follows: "Dhcp6": { "hosts-database": { "readonly": true, ... }, ... } Setting this parameter to false would configure the database backend to operate in "read-write" mode, which is also a default configuration if the parameter is not specified. The readonly parameter is currently only supported for MySQL and PostgreSQL databases.
Interface Selection The DHCPv6 server has to be configured to listen on specific network interfaces. The simplest network interface configuration instructs the server to listen on all available interfaces: "Dhcp6": { "interfaces-config": { "interfaces": [ "*" ] } ... } The asterisk plays the role of a wildcard and means "listen on all interfaces". However, it is usually a good idea to explicitly specify interface names: "Dhcp6": { "interfaces-config": { "interfaces": [ "eth1", "eth3" ] }, ... } It is possible to use wildcard interface name (asterisk) concurrently with the actual interface names: "Dhcp6": { "interfaces-config": { "interfaces": [ "eth1", "eth3", "*" ] }, ... } It is anticipated that this will form of usage only be used where it is desired to temporarily override a list of interface names and listen on all interfaces.
IPv6 Subnet Identifier The subnet identifier is a unique number associated with a particular subnet. In principle, it is used to associate clients' leases with their respective subnets. When a subnet identifier is not specified for a subnet being configured, it will be automatically assigned by the configuration mechanism. The identifiers are assigned from 1 and are monotonically increased for each subsequent subnet: 1, 2, 3 .... If there are multiple subnets configured with auto-generated identifiers and one of them is removed, the subnet identifiers may be renumbered. For example: if there are four subnets and the third is removed the last subnet will be assigned the identifier that the third subnet had before removal. As a result, the leases stored in the lease database for subnet 3 are now associated with subnet 4, something that may have unexpected consequences. It is planned to implement a mechanism to preserve auto-generated subnet ids in a future version of Kea. However, the only remedy for this issue at present is to manually specify a unique identifier for each subnet. The following configuration will assign the specified subnet identifier to the newly configured subnet: "Dhcp6": { "subnet6": [ { "subnet": "2001:db8:1::/64", "id": 1024, ... } ] } This identifier will not change for this subnet unless the "id" parameter is removed or set to 0. The value of 0 forces auto-generation of the subnet identifier.
Unicast Traffic Support When the DHCPv6 server starts, by default it listens to the DHCP traffic sent to multicast address ff02::1:2 on each interface that it is configured to listen on (see ). In some cases it is useful to configure a server to handle incoming traffic sent to the global unicast addresses as well. The most common reason for this is to have relays send their traffic to the server directly. To configure the server to listen on a specific unicast address, nn interface name can be optionally followed by a slash, followed by the global unicast address on which the server should listen. The server listens to this address in addition to normal link-local binding and listening on ff02::1:2 address. The sample configuration below shows how to listen on 2001:db8::1 (a global address) configured on the eth1 interface. "Dhcp6": { "interfaces-config": { "interfaces": [ "eth1/2001:db8::1" ] }, ... "option-data": [ { "name": "unicast", "data": "2001:db8::1" } ], ... } This configuration will cause the server to listen on eth1 on the link-local address, the multicast group (ff02::1:2) and 2001:db8::1. Usually unicast support is associated with a server unicast option which allows clients to send unicast messages to the server. The example above includes a server unicast option specification which will cause the client to send messages to the specified unicast address. It is possible to mix interface names, wildcards and interface name/addresses in the list of interfaces. It is not possible however to specify more than one unicast address on a given interface. Care should be taken to specify proper unicast addresses. The server will attempt to bind to the addresses specified without any additional checks. This approach has selected on purpose to allow the software to communicate over uncommon addresses if so desired.
Subnet and Address Pool The main role of a DHCPv6 server is address assignment. For this, the server has to be configured with at least one subnet and one pool of dynamic addresses to be managed. For example, assume that the server is connected to a network segment that uses the 2001:db8:1::/64 prefix. The Administrator of that network has decided that addresses from range 2001:db8:1::1 to 2001:db8:1::ffff are going to be managed by the Dhcp6 server. Such a configuration can be achieved in the following way: "Dhcp6": { "subnet6": [ { "subnet": "2001:db8:1::/64", "pools": [ { "pool": "2001:db8:1::1-2001:db8:1::ffff" } ], ... } ] } Note that subnet is defined as a simple string, but the pools parameter is actually a list of pools: for this reason, the pool definition is enclosed in square brackets, even though only one range of addresses is specified. Each pool is a structure that contains the parameters that describe a single pool. Currently there is only one parameter, pool, which gives the range of addresses in the pool. Additional parameters will be added in future releases of Kea. It is possible to define more than one pool in a subnet: continuing the previous example, further assume that 2001:db8:1:0:5::/80 should also be managed by the server. It could be written as 2001:db8:1:0:5:: to 2001:db8:1::5:ffff:ffff:ffff, but typing so many 'f's is cumbersome. It can be expressed more simply as 2001:db8:1:0:5::/80. Both formats are supported by Dhcp6 and can be mixed in the pool list. For example, one could define the following pools: "Dhcp6": { "subnet6": [ { "subnet": "2001:db8:1::/64", "pools": [ { "pool": "2001:db8:1::1-2001:db8:1::ffff" }, { "pool": "2001:db8:1:05::/80" } ], ... } ] } White space in pool definitions is ignored, so spaces before and after the hyphen are optional. They can be used to improve readability. The number of pools is not limited, but for performance reasons it is recommended to use as few as possible. The server may be configured to serve more than one subnet. To add a second subnet, use a command similar to the following: "Dhcp6": { "subnet6": [ { "subnet": "2001:db8:1::/64", "pools": [ { "pool": "2001:db8:1::1-2001:db8:1::ffff" } ] }, { "subnet": "2001:db8:2::/64", "pools": [ { "pool": "2001:db8:2::/64" } ] }, ... ] } In this example, we allow the server to dynamically assign all addresses available in the whole subnet. Although rather wasteful, it is certainly a valid configuration to dedicate the whole /64 subnet for that purpose. Note that the Kea server does not preallocate the leases, so there is no danger in using gigantic address pools. When configuring a DHCPv6 server using prefix/length notation, please pay attention to the boundary values. When specifying that the server can use a given pool, it will also be able to allocate the first (typically network address) address from that pool. For example, for pool 2001:db8:2::/64 the 2001:db8:2:: address may be assigned as well. If you want to avoid this, use the "min-max" notation.
Subnet and Prefix Delegation Pools Subnets may also be configured to delegate prefixes, as defined in RFC 3633. A subnet may have one or more prefix delegation pools. Each pool has a prefixed address, which is specified as a prefix (prefix) and a prefix length (prefix-len), as well as a delegated prefix length (delegated-len). The delegated length must not be shorter (that is it must be numerically greater or equal) than the prefix length. If both the delegated and prefix lengths are equal, the server will be able to delegate only one prefix. The delegated prefix does not have to match the subnet prefix. Below is a sample subnet configuration which enables prefix delegation for the subnet: "Dhcp6": { "subnet6": [ { "subnet": "2001:d8b:1::/64", "pd-pools": [ { "prefix": "3000:1::", "prefix-len": 64, "delegated-len": 96 } ] } ], ... }
Standard DHCPv6 Options One of the major features of a DHCPv6 server is to provide configuration options to clients. Although there are several options that require special behavior, most options are sent by the server only if the client explicitly requests them. The following example shows how to configure DNS servers, one of the most frequently used options. Options specified in this way are considered global and apply to all configured subnets. "Dhcp6": { "option-data": [ { "name": "dns-servers", "code": 23, "space": "dhcp6", "csv-format": true, "data": "2001:db8::cafe, 2001:db8::babe" }, ... ] } The option-data line creates a new entry in the option-data table. This table contains information on all global options that the server is supposed to configure in all subnets. The name line specifies the option name. (For a complete list of currently supported names, see .) The next line specifies the option code, which must match one of the values from that list. The line beginning with space specifies the option space, which must always be set to "dhcp6" as these are standard DHCPv6 options. For other name spaces, including custom option spaces, see . The following line specifies the format in which the data will be entered: use of CSV (comma separated values) is recommended. Finally, the data line gives the actual value to be sent to clients. Data is specified as normal text, with values separated by commas if more than one value is allowed. Options can also be configured as hexadecimal values. If "csv-format" is set to false, the option data must be specified as a string of hexadecimal numbers. The following commands configure the DNS-SERVERS option for all subnets with the following addresses: 2001:db8:1::cafe and 2001:db8:1::babe. "Dhcp6": { "option-data": [ { "name": "dns-servers", "code": 23, "space": "dhcp6", "csv-format": false, "data": "2001 0DB8 0001 0000 0000 0000 0000 CAFE 2001 0DB8 0001 0000 0000 0000 0000 BABE" }, ... ] } The value for the setting of the "data" element is split across two lines in this example for clarity: when entering the command, the whole string should be entered on the same line. Care should be taken to use proper encoding when using hexadecimal format as Kea's ability to validate data correctness in hexadecimal is limited. Most of the parameters in the "option-data" structure are optional and can be omitted in some circumstances as discussed in the . It is possible to override options on a per-subnet basis. If clients connected to most of your subnets are expected to get the same values of a given option, you should use global options: you can then override specific values for a small number of subnets. On the other hand, if you use different values in each subnet, it does not make sense to specify global option values (Dhcp6/option-data), rather you should set only subnet-specific values (Dhcp6/subnet[X]/option-data[Y]). The following commands override the global DNS servers option for a particular subnet, setting a single DNS server with address 2001:db8:1::3. "Dhcp6": { "subnet6": [ { "option-data": [ { "name": "dns-servers", "code": 23, "space": "dhcp6", "csv-format": true, "data": "2001:db8:1::3" }, ... ], ... }, ... ], ... } The currently supported standard DHCPv6 options are listed in . The "Name" and "Code" are the values that should be used as a name in the option-data structures. "Type" designates the format of the data: the meanings of the various types is given in . Experimental options (like standard options but with a code which was not assigned by IANA) are listed in . Some options are designated as arrays, which means that more than one value is allowed in such an option. For example the option dns-servers allows the specification of more than one IPv6 address, allowing clients to obtain the addresses of multiple DNS servers. The describes the configuration syntax to create custom option definitions (formats). It is generally not allowed to create custom definitions for standard options, even if the definition being created matches the actual option format defined in the RFCs. There is an exception from this rule for standard options for which Kea does not yes provide a definition. In order to use such options, a server administrator must create a definition as described in in the 'dhcp6' option space. This definition should match the option format described in the relevant RFC but the configuration mechanism would allow any option format as it has no means to validate the format at the moment. List of Standard DHCPv6 Options NameCodeTypeArray?preference7uint8falseunicast12ipv6-addressfalsevendor-opts17uint32false --> sip-server-dns21fqdntruesip-server-addr22ipv6-addresstruedns-servers23ipv6-addresstruedomain-search24fqdntruenis-servers27ipv6-addresstruenisp-servers28ipv6-addresstruenis-domain-name29fqdntruenisp-domain-name30fqdntruesntp-servers31ipv6-addresstrueinformation-refresh-time32uint32falsebcmcs-server-dns33fqdntruebcmcs-server-addr34ipv6-addresstruegeoconf-civic36record (uint8, uint16, binary)falseremote-id37record (uint32, binary)falsesubscriber-id38binaryfalseclient-fqdn39record (uint8, fqdn)falsepana-agent40ipv6-addresstruenew-posix-timezone41stringfalsenew-tzdb-timezone42stringfalseero43uint16truelq-query44record (uint8, ipv6-address)falseclient-data45emptyfalseclt-time46uint32falselq-relay-data47record (ipv6-address, binary)falselq-client-link48ipv6-addresstruebootfile-url59stringfalsebootfile-param60binaryfalseclient-arch-type61uint16truenii62record (uint8, uint8, uint8)falseerp-local-domain-name65fqdnfalsersoo66emptyfalseclient-linklayer-addr79binaryfalsedhcp4o6-server-addr88ipv6-addresstrue
List of Experimental DHCPv6 Options NameCodeTypeArray?public-key701binaryfalsecertificate702binaryfalsesignature703record (uint8, uint8, binary)falsetimestamp704binaryfalse
Custom DHCPv6 Options It is possible to define options in addition to the standard ones. Assume that we want to define a new DHCPv6 option called "foo" which will have code 100 and which will convey a single unsigned 32 bit integer value. We can define such an option by using the following commands: "Dhcp6": { "option-def": [ { "name": "foo", "code": 100, "type": "uint32", "array": false, "record-types": "", "space": "dhcp6", "encapsulate": "" }, ... ], ... } The "false" value of the array parameter determines that the option does NOT comprise an array of "uint32" values but rather a single value. Two other parameters have been left blank: record-types and encapsulate. The former specifies the comma separated list of option data fields if the option comprises a record of data fields. The record-types value should be non-empty if the type is set to "record". Otherwise it must be left blank. The latter parameter specifies the name of the option space being encapsulated by the particular option. If the particular option does not encapsulate any option space it should be left blank. Note that the above example only defines the format of the new option, it does not set its value(s). The name, code and type parameters are required, all others are optional. The array default value is false. The record-types and encapsulate default values are blank (i.e. ""). The default space is "dhcp6". Once the new option format is defined, its value is set in the same way as for a standard option. For example the following commands set a global value that applies to all subnets. "Dhcp6": { "option-data": [ { "name": "foo", "code": 100, "space": "dhcp6", "csv-format": true, "data": "12345" }, ... ], ... } New options can take more complex forms than simple use of primitives (uint8, string, ipv6-address etc): it is possible to define an option comprising a number of existing primitives. For example, assume we want to define a new option that will consist of an IPv6 address, followed by an unsigned 16 bit integer, followed by a boolean value, followed by a text string. Such an option could be defined in the following way: "Dhcp6": { "option-def": [ { "name": "bar", "code": 101, "space": "dhcp6", "type": "record", "array": false, "record-types": "ipv6-address, uint16, boolean, string", "encapsulate": "" }, ... ], ... } The "type" is set to "record" to indicate that the option contains multiple values of different types. These types are given as a comma-separated list in the "record-types" field and should be those listed in . The values of the option are set as follows: "Dhcp6": { "option-data": [ { "name": "bar", "space": "dhcp6", "code": 101, "csv-format": true, "data": "2001:db8:1::10, 123, false, Hello World" } ], ... } csv-format is set true to indicate that the data field comprises a command-separated list of values. The values in the "data" must correspond to the types set in the "record-types" field of the option definition. In the general case, boolean values are specified as true or false, without quotes. Some specific boolean parameters may accept also "true", "false", 0, 1, "0" and "1". Future versions of Kea will accept all those values for all boolean parameters.
DHCPv6 Vendor-Specific Options Currently there are two option spaces defined for the DHCPv6 daemon: "dhcp6" (for top level DHCPv6 options) and "vendor-opts-space", which is empty by default, but in which options can be defined. Those options will be carried in the Vendor-Specific Information option (code 17). The following examples show how to define an option "foo" with code 1 that consists of an IPv6 address, an unsigned 16 bit integer and a string. The "foo" option is conveyed in a Vendor-Specific Information option. This option comprises a single uint32 value that is set to "12345". The sub-option "foo" follows the data field holding this value. "Dhcp6": { "option-def": [ { "name": "foo", "code": 1, "space": "vendor-opts-space", "type": "record", "array": false, "record-types": "ipv6-address, uint16, string", "encapsulate": "" } ], ... } (Note that the option space is set to vendor-opts-space.) Once the option format is defined, the next step is to define actual values for that option: "Dhcp6": { "option-data": [ { "name": "foo", "space": "vendor-opts-space", "data": "2001:db8:1::10, 123, Hello World" }, ... ], ... } We should also define a value (enterprise-number) for the Vendor-specific Information option, that conveys our option "foo". "Dhcp6": { "option-data": [ ..., { "name": "vendor-opts", "data": "12345" } ], ... } Alternatively, the option can be specified using its code. "Dhcp6": { "option-data": [ ..., { "code": 17, "data": "12345" } ], ... }
Nested DHCPv6 Options (Custom Option Spaces) It is sometimes useful to define completely new option spaces. This is useful if the user wants their new option to convey sub-options that use a separate numbering scheme, for example sub-options with codes 1 and 2. Those option codes conflict with standard DHCPv6 options, so a separate option space must be defined. Note that it is not required to create a new option space when defining sub-options for a standard option because it is created by default if the standard option is meant to convey any sub-options (see ). Assume that we want to have a DHCPv6 option called "container" with code 102 that conveys two sub-options with codes 1 and 2. First we need to define the new sub-options: "Dhcp6": { "option-def": [ { "name": "subopt1", "code": 1, "space": "isc", "type": "ipv6-address", "record-types": "", "array": false, "encapsulate": "" }, { "name": "subopt2", "code": 2, "space": "isc", "type": "string", "record-types": "", "array": false "encapsulate": "" } ], ... } Note that we have defined the options to belong to a new option space (in this case, "isc"). The next step is to define a regular DHCPv6 option and specify that it should include options from the isc option space: "Dhcp6": { "option-def": [ ..., { "name": "container", "code": 102, "space": "dhcp6", "type": "empty", "array": false, "record-types": "", "encapsulate": "isc" } ], ... } The name of the option space in which the sub-options are defined is set in the encapsulate field. The type field is set to empty which limits this option to only carrying data in sub-options. Finally, we can set values for the new options: "Dhcp6": { "option-data": [ { "name": "subopt1", "code": 1, "space": "isc", "data": "2001:db8::abcd" }, } "name": "subopt2", "code": 2, "space": "isc", "data": "Hello world" }, { "name": "container", "code": 102, "space": "dhcp6" } ], ... } Note that it is possible to create an option which carries some data in addition to the sub-options defined in the encapsulated option space. For example, if the "container" option from the previous example was required to carry an uint16 value as well as the sub-options, the "type" value would have to be set to "uint16" in the option definition. (Such an option would then have the following data structure: DHCP header, uint16 value, sub-options.) The value specified with the "data" parameter — which should be a valid integer enclosed in quotes, e.g. "123" — would then be assigned to the uint16 field in the "container" option.
Unspecified Parameters for DHCPv6 Option Configuration In many cases it is not required to specify all parameters for an option configuration and the default values can be used. However, it is important to understand the implications of not specifying some of them as it may result in configuration errors. The list below explains the behavior of the server when a particular parameter is not explicitly specified: name - the server requires an option name or option code to identify an option. If this parameter is unspecified, the option code must be specified. code - the server requires an option name or option code to identify an option. This parameter may be left unspecified if the name parameter is specified. However, this also requires that the particular option has its definition (it is either a standard option or an administrator created a definition for the option using an 'option-def' structure), as the option definition associates an option with a particular name. It is possible to configure an option for which there is no definition (unspecified option format). Configuration of such options requires the use of option code. space - if the option space is unspecified it will default to 'dhcp6' which is an option space holding DHCPv6 standard options. data - if the option data is unspecified it defaults to an empty value. The empty value is mostly used for the options which have no payload (boolean options), but it is legal to specify empty values for some options which carry variable length data and which spec allows for the length of 0. For such options, the data parameter may be omitted in the configuration. csv-format - if this value is not specified and the definition for the particular option exists, the server will assume that the option data is specified as a list of comma separated values to be assigned to individual fields of the DHCP option. If the definition does not exist for this option, the server will assume that the data parameter contains the option payload in the binary format (represented as a string of hexadecimal digits). Note that not specifying this parameter doesn't imply that it defaults to a fixed value, but the configuration data interpretation also depends on the presence of the option definition. An administrator must be aware if the definition for the particular option exists when this parameter is not specified. It is generally recommended to not specify this parameter only for the options for which the definition exists, e.g. standard options. Setting csv-format to an explicit value will cause the server to strictly check the format of the option data specified.
IPv6 Subnet Selection The DHCPv6 server may receive requests from local (connected to the same subnet as the server) and remote (connecting via relays) clients. As the server may have many subnet configurations defined, it must select an appropriate subnet for a given request. The server can not assume which of the configured subnets are local. In IPv4 it is possible as there is a reasonable expectation that the server will have a (global) IPv4 address configured on the interface, and can use that information to detect whether a subnet is local or not. That assumption is not true in IPv6: the DHCPv6 server must be able to operate while only using link-local addresses. Therefore an optional interface parameter is available within a subnet definition to designate that a given subnet is local, i.e. reachable directly over the specified interface. For example the server that is intended to serve a local subnet over eth0 may be configured as follows: "Dhcp6": { "subnet6": [ { "subnet": "2001:db8:beef::/48", "pools": [ { "pool": "2001:db8:beef::/48" } ], "interface": "eth0" } ], ... }
Rapid Commit The Rapid Commit option, described in RFC 3315, is supported by the Kea DHCPv6 server. However, support is disabled by default for all subnets. It can be enabled for a particular subnet using the rapid-commit parameter as shown below: "Dhcp6": { "subnet6": [ { "subnet": "2001:db8:beef::/48", "rapid-commit": true, "pools": [ { "pool": "2001:db8:beef::1-2001:db8:beef::10" } ], } ], ... } This setting only affects the subnet for which the rapid-commit is set to true. For clients connected to other subnets, the server will ignore the Rapid Commit option sent by the client and will follow the 4-way exchange procedure, i.e. respond with an Advertise for a Solicit containing a Rapid Commit option.
DHCPv6 Relays A DHCPv6 server with multiple subnets defined must select the appropriate subnet when it receives a request from a client. For clients connected via relays, two mechanisms are used: The first uses the linkaddr field in the RELAY_FORW message. The name of this field is somewhat misleading in that it does not contain a link-layer address: instead, it holds an address (typically a global address) that is used to identify a link. The DHCPv6 server checks if the address belongs to a defined subnet and, if it does, that subnet is selected for the client's request. The second mechanism is based on interface-id options. While forwarding a client's message, relays may insert an interface-id option into the message that identifies the interface on the relay that received the message. (Some relays allow configuration of that parameter, but it is sometimes hardcoded and may range from the very simple (e.g. "vlan100") to the very cryptic: one example seen on real hardware was "ISAM144|299|ipv6|nt:vp:1:110"). The server can use this information to select the appropriate subnet. The information is also returned to the relay which then knows the interface to use to transmit the response to the client. In order for this to work successfully, the relay interface IDs must be unique within the network and the server configuration must match those values. When configuring the DHCPv6 server, it should be noted that two similarly-named parameters can be configured for a subnet: interface defines which local network interface can be used to access a given subnet. interface-id specifies the content of the interface-id option used by relays to identify the interface on the relay to which the response packet is sent. The two are mutually exclusive: a subnet cannot be both reachable locally (direct traffic) and via relays (remote traffic). Specifying both is a configuration error and the DHCPv6 server will refuse such a configuration. The following example configuration shows how to specify an interface-id with a value of "vlan123". "Dhcp6": { "subnet6": [ { "subnet": "2001:db8:beef::/48", "pools": [ { "pool": "2001:db8:beef::/48" } ], "interface-id": "vlan123" } ], ... }
Relay-Supplied Options RFC 6422 defines a mechanism called Relay-Supplied DHCP Options. In certain cases relay agents are the only entities that may have specific information. They can insert options when relaying messages from the client to the server. The server will then do certain checks and copy those options to the response that will be sent to the client. There are certain conditions that must be met for the option to be included. First, the server must not provide the option itself. In other words, if both relay and server provide an option, the server always takes precedence. Second, the option must be RSOO-enabled. IANA maintains a list of RSOO-enabled options here. However, there may be cases when system administrators want to echo other options. Kea can be instructed to treat other options as RSOO-enabled. For example, to mark options 110, 120 and 130 as RSOO-enabled, the following syntax should be used: "Dhcp6": { "relay-supplied-options": [ "110", "120", "130" ], ... } As of March 2015, only option 65 is RSOO-enabled by IANA. This option will always be treated as such and there's no need to explicitly mark it. Also, when enabling standard options, it is possible to use their names, rather than option code, e.g. (e.g. use dns-servers instead of 23). See for the names. In certain cases it could also work for custom options, but due to the nature of the parser code this may be unreliable and should be avoided.
Client Classification in DHCPv6 The DHCPv6 server includes support for client classification. For a deeper discussion of the classification process see . In certain cases it is useful to differentiate between different types of clients and treat them accordingly. It is envisaged that client classification will be used for changing the behavior of almost any part of the DHCP message processing, including the assignment of leases from different pools, the assignment of different options (or different values of the same options) etc. In the current release of the software however, there are only two mechanisms that take advantage of client classification: subnet selection and assignment of different options. Kea can be instructed to limit access to given subnets based on class information. This is particularly useful for cases where two types of devices share the same link and are expected to be served from two different subnets. The primary use case for such a scenario is cable networks. Here, there are two classes of devices: the cable modem itself, which should be handed a lease from subnet A and all other devices behind the modem that should get a lease from subnet B. That segregation is essential to prevent overly curious users from playing with their cable modems. For details on how to set up class restrictions on subnets, see . The process of doing classification is conducted in three steps. The first step is to assess an incoming packet and assign it to zero or more classes. The second step is to choose a subnet, possibly based on the class information. The third step is to assign options again possibly based on the class information. There are two methods of doing classification. The first is automatic and relies on examining the values in the vendor class options. Information from these options is extracted and a class name is constructed from it and added to the class list for the packet. The second allows you to specify an expression that is evaluated for each packet. If the result is true the packet is a member of the class. Care should be taken with client classification as it is easy for clients that do not meet class criteria to be denied any service altogether.
Defining and Using Custom Classes The following example shows how to configure a class using an expression and a subnet making use of that class. This configuration defines the class named "Client_enterprise". It is comprised of all clients whose client identifiers start with the given hex string (which would indicate a DUID based on an enterprise id of 0xAABBCCDD). They will be given an address from 2001:db8:1::0 to 2001:db8:1::FFFF and the addresses of their DNS servers set to 2001:db8:0::1 and 2001:db8:2::1. "Dhcp6": { "client-classes": [ { "name": "Client_enterprise", "test": "substring(option[1].hex,0,6) == 0x0002AABBCCDD'", "option-data": [ { "name": "dns-servers", "code": 23, "space": "dhcp6", "csv-format": true, "data": "2001:db8:0::1, 2001:db8:2::1" } ] }, ... ], "subnet6": [ { "subnet": "2001:db8:1::/64", "pools": [ { "pool": "2001:db8:1::-2001:db8:1::ffff" } ], "client-class": "Client_enterprise" } ], ... } This example shows a configuration using an automatically generated "VENDOR_CLASS_" class. The Administrator of the network has decided that addresses from range 2001:db8:1::1 to 2001:db8:1::ffff are going to be managed by the Dhcp6 server and only clients belonging to the eRouter1.0 client class are allowed to use that pool. "Dhcp6": { "subnet6": [ { "subnet": "2001:db8:1::/64", "pools": [ { "pool": "2001:db8:1::-2001:db8:1::ffff" } ], "client-class": "VENDOR_CLASS_eRouter1.0" } ], ... }
DDNS for DHCPv6 As mentioned earlier, kea-dhcp6 can be configured to generate requests to the DHCP-DDNS server (referred to here as "D2") to update DNS entries. These requests are known as NameChangeRequests or NCRs. Each NCR contains the following information: Whether it is a request to add (update) or remove DNS entries Whether the change requests forward DNS updates (AAAA records), reverse DNS updates (PTR records), or both. The FQDN, lease address, and DHCID The parameters controlling the generation of NCRs for submission to D2 are contained in the dhcp-ddns section of the kea-dhcp6 configuration. The mandatory parameters for the DHCP DDNS configuration are enable-updates which is unconditionally required, and qualifying-suffix which has no default value and is required when enable-updates is set to true. The two (disabled and enabled) minimal DHCP DDNS configurations are: "Dhcp6": { "dhcp-ddns": { "enable-updates": false }, ... } and for example: "Dhcp6": { "dhcp-ddns": { "enable-updates": true, "qualifying-suffix": "example." }, ... } The default values for the "dhcp-ddns" section are as follows: "server-ip": "127.0.0.1" "server-port": 53001 "sender-ip": "" "sender-port": 0 "max-queue-size": 1024 "ncr-protocol": "UDP" "ncr-format": "JSON" "override-no-update": false "override-client-update": false "replace-client-name": "never" "generated-prefix": "myhost"
DHCP-DDNS Server Connectivity In order for NCRs to reach the D2 server, kea-dhcp6 must be able to communicate with it. kea-dhcp6 uses the following configuration parameters to control this communication: enable-updates - determines whether or not kea-dhcp6 will generate NCRs. If missing, this value is assumed to be false hence DDNS updates are disabled. To enable DDNS updates set this value to true: server-ip - IP address on which D2 listens for requests. The default is the local loopback interface at address 127.0.0.1. You may specify either an IPv4 or IPv6 address. server-port - port on which D2 listens for requests. The default value is 53001. sender-ip - IP address which kea-dhcp6 should use to send requests to D2. The default value is blank which instructs kea-dhcp6 to select a suitable address. sender-port - port which kea-dhcp6 should use to send requests to D2. The default value of 0 instructs kea-dhcp6 to select a suitable port. max-queue-size - maximum number of requests allowed to queue waiting to be sent to D2. This value guards against requests accumulating uncontrollably if they are being generated faster than they can be delivered. If the number of requests queued for transmission reaches this value, DDNS updating will be turned off until the queue backlog has been sufficiently reduced. The intent is to allow kea-dhcp6 to continue lease operations. The default value is 1024. ncr-protocol - socket protocol use when sending requests to D2. Currently only UDP is supported. TCP may be available in an upcoming release. ncr-format - packet format to use when sending requests to D2. Currently only JSON format is supported. Other formats may be available in future releases. By default, kea-dhcp-ddns is assumed to running on the same machine as kea-dhcp6, and all of the default values mentioned above should be sufficient. If, however, D2 has been configured to listen on a different address or port, these values must altered accordingly. For example, if D2 has been configured to listen on 2001:db8::5 port 900, the following configuration would be required: "Dhcp6": { "dhcp-ddns": { "server-ip": "2001:db8::5", "server-port": 900, ... }, ... }
When Does kea-dhcp6 Generate a DDNS Request? kea-dhcp6 follows the behavior prescribed for DHCP servers in RFC 4704. It is important to keep in mind that kea-dhcp6 provides the initial decision making of when and what to update and forwards that information to D2 in the form of NCRs. Carrying out the actual DNS updates and dealing with such things as conflict resolution are within the purview of D2 itself (). This section describes when kea-dhcp6 will generate NCRs and the configuration parameters that can be used to influence this decision. It assumes that the enable-updates parameter is true. Currently the interface between kea-dhcp6 and D2 only supports requests which update DNS entries for a single IP address. If a lease grants more than one address, kea-dhcp6 will create the DDNS update request for only the first of these addresses. Support for multiple address mappings may be provided in a future release. In general, kea-dhcp6 will generate DDNS update requests when: A new lease is granted in response to a REQUEST An existing lease is renewed but the FQDN associated with it has changed. An existing lease is released in response to a RELEASE In the second case, lease renewal, two DDNS requests will be issued: one request to remove entries for the previous FQDN and a second request to add entries for the new FQDN. In the last case, a lease release, a single DDNS request to remove its entries will be made. The decision making involved when granting a new lease the first case) is more involved. When a new lease is granted, kea-dhcp6 will generate a DDNS update request only if the REQUEST contains the FQDN option (code 39). By default kea-dhcp6 will respect the FQDN N and S flags specified by the client as shown in the following table: Default FQDN Flag Behavior Client Flags:N-S Client Intent Server Response Server Flags:N-S-O 0-0 Client wants to do forward updates, server should do reverse updates Server generates reverse-only request 1-0-0 0-1 Server should do both forward and reverse updates Server generates request to update both directions 0-1-0 1-0 Client wants no updates done Server does not generate a request 1-0-0
The first row in the table above represents "client delegation". Here the DHCP client states that it intends to do the forward DNS updates and the server should do the reverse updates. By default, kea-dhcp6 will honor the client's wishes and generate a DDNS request to D2 to update only reverse DNS data. The parameter, override-client-update, can be used to instruct the server to override client delegation requests. When this parameter is true, kea-dhcp6 will disregard requests for client delegation and generate a DDNS request to update both forward and reverse DNS data. In this case, the N-S-O flags in the server's response to the client will be 0-1-1 respectively. (Note that the flag combination N=1, S=1 is prohibited according to RFC 4702. If such a combination is received from the client, the packet will be dropped by kea-dhcp6.) To override client delegation, set the following values in the configuration: "Dhcp6": { "dhcp-ddns": { "override-client-update": true, ... }, ... } The third row in the table above describes the case in which the client requests that no DNS updates be done. The parameter, override-no-update, can be used to instruct the server to disregard the client's wishes. When this parameter is true, kea-dhcp6 will generate DDNS update requests to kea-dhcp-ddns even if the client requests no updates be done. The N-S-O flags in the server's response to the client will be 0-1-1. To override client delegation, issue the following commands: "Dhcp6": { "dhcp-ddns": { "override-no-update": true, ... }, ... }
kea-dhcp6 Name Generation for DDNS Update Requests Each NameChangeRequest must of course include the fully qualified domain name whose DNS entries are to be affected. kea-dhcp6 can be configured to supply a portion or all of that name based upon what it receives from the client. The default rules for constructing the FQDN that will be used for DNS entries are: If the DHCPREQUEST contains the client FQDN option, the candidate name is taken from there. If the candidate name is a partial (i.e. unqualified) name then add a configurable suffix to the name and use the result as the FQDN. If the candidate name provided is empty, generate an FQDN using a configurable prefix and suffix. If the client provided neither option, then no DNS action will be taken. These rules can amended by setting the replace-client-name parameter which provides the following modes of behavior: never - Use the name the client sent. If the client sent no name, do not generate one. This is the default mode. always - Replace the name the client sent. If the client sent no name, generate one for the client. when-present - Replace the name the client sent. If the client sent no name, do not generate one. when-not-present - Use the name the client sent. If the client sent no name, generate one for the client. Note that formerly, this parameter was a boolean and permitted only values of true and false. Boolean values will still be accepted but may eventually be deprecated. A value of true equates to when-present, false equates to never. For example, To instruct kea-dhcp6 to always generate the FQDN for a client, set the parameter replace-client-name to always as follows: "Dhcp6": { "dhcp-ddns": { "replace-client-name": "always", ... }, ... } The prefix used in the generation of an FQDN is specified by the generated-prefix parameter. The default value is "myhost". To alter its value, simply set it to the desired string: "Dhcp6": { "dhcp-ddns": { "generated-prefix": "another.host", ... }, ... } The suffix used when generating an FQDN or when qualifying a partial name is specified by the qualifying-suffix parameter. This parameter has no default value, thus it is mandatory when DDNS updates are enabled. To set its value simply set it to the desired string: "Dhcp6": { "dhcp-ddns": { "qualifying-suffix": "foo.example.org", ... }, ... }
When qualifying a partial name, kea-dhcp6 will construct a name with the format: [candidate-name].[qualifying-suffix]. where candidate-name is the partial name supplied in the REQUEST. For example, if FQDN domain name value was "some-computer" and qualifying-suffix "example.com", the generated FQDN would be: some-computer.example.com. When generating the entire name, kea-dhcp6 will construct name of the format: [generated-prefix]-[address-text].[qualifying-suffix]. where address-text is simply the lease IP address converted to a hyphenated string. For example, if lease address is 3001:1::70E, the qualifying suffix "example.com", and the default value is used for generated-prefix, the generated FQDN would be: myhost-3001-1--70E.example.com.
DHCPv4-over-DHCPv6: DHCPv6 Side The support of DHCPv4-over-DHCPv6 transport is described in RFC 7341 and is implemented using cooperating DHCPv4 and DHCPv6 servers. This section is about the configuration of the DHCPv6 side (the DHCPv4 side is described in ). DHCPv4-over-DHCPv6 support is experimental and the details of the inter-process communication can change: both the DHCPv4 and DHCPv6 sides should be running the same version of Kea. There is only one specific parameter for the DHCPv6 side: dhcp4o6-port which specifies the first of the two consecutive ports of the UDP sockets used for the communication between the DHCPv6 and DHCPv4 servers (the DHCPv6 server is bound to ::1 on port and connected to ::1 on port + 1). Two other configuration entries are in general required: unicast traffic support (see ) and DHCP 4o6 server address option (name "dhcp4o6-server-addr", code 88). The following configuration was used during some tests: { # DHCPv6 conf "Dhcp6": { "interfaces-config": { "interfaces": [ "eno33554984/2001:db8:1:1::1" ] }, "lease-database": { "type": "memfile", "name": "leases6" }, "preferred-lifetime": 3000, "valid-lifetime": 4000, "renew-timer": 1000, "rebind-timer": 2000, "subnet6": [ { "subnet": "2001:db8:1:1::/64", "interface": "eno33554984", "pools": [ { "pool": "2001:db8:1:1::1:0/112" } ] } ], "dhcp4o6-port": 6767, "option-data": [ { "name": "dhcp4o6-server-addr", "code": 88, "space": "dhcp6", "csv-format": true, "data": "2001:db8:1:1::1" } ] }, "Logging": { "loggers": [ { "name": "kea-dhcp6", "output_options": [ { "output": "/tmp/kea-dhcp6.log" } ], "severity": "DEBUG", "debuglevel": 0 } ] } } Relayed DHCPv4-QUERY DHCPv6 messages are not yet supported.
Host Reservation in DHCPv6 There are many cases where it is useful to provide a configuration on a per host basis. The most obvious one is to reserve specific, static IPv6 address or/and prefix for exclusive use by a given client (host) ‐ returning client will get the same address or/and prefix every time and other clients will never get that address. Note that there may be cases when the new reservation has been made for the client for the address or prefix being currently in use by another client. We call this situation a "conflict". The conflicts get resolved automatically over time as described in the subsequent sections. Once conflict is resolved, the client will keep receiving the reserved configuration when it renews. Another example when the host reservations are applicable is when a host has specific requirements, e.g. a printer that needs additional DHCP options or a cable modem needs specific parameters. Yet another possible use case for host reservation is to define unique names for hosts. Hosts reservations are defined as parameters for each subnet. Each host can be identified by either DUID or its hardware/MAC address. See for details. There is an optional reservations array in the subnet6 structure. Each element in that array is a structure, that holds information about a single host. In particular, the structure has an identifier that uniquely identifies a host. In the DHCPv6 context, such an identifier is usually a DUID, but can also be a hardware or MAC address. Also, either one or more addresses or prefixes may be specified. It is possible to specify a hostname and DHCPv6 options for a given host. The following example shows how to reserve addresses and prefixes for specific hosts: "subnet6": [ { "subnet": "2001:db8:1::/48", "pools": [ { "pool": "2001:db8:1::/80" } ], "pd-pools": [ { "prefix": "2001:db8:1:8000::", "prefix-len": 56, "delegated-len": 64 } ], "reservations": [ { "duid": "01:02:03:04:05:0A:0B:0C:0D:0E", "ip-addresses": [ "2001:db8:1::100" ] }, { "hw-address": "00:01:02:03:04:05", "ip-addresses": [ "2001:db8:1::101, 2001:db8:1::102" ] }, { "duid": "01:02:03:04:05:06:07:08:09:0A", "ip-addresses": [ "2001:db8:1::103" ], "prefixes": [ "2001:db8:2:abcd::/64" ], "hostname": "foo.example.com" } ] } ] This example includes reservations for three different clients. The first reservation is made for the address 2001:db8:1::100 for a client using DUID 01:02:03:04:05:0A:0B:0C:0D:0E. The second reservation is made for two addresses 2001:db8:1::101 and 2001:db8:1::102 for a client using MAC address 00:01:02:03:04:05. Lastly, address 2001:db8:1::103 and prefix 2001:db8:2:abcd::/64 are reserved for a client using DUID 01:02:03:04:05:06:07:08:09:0A. The last reservation also assigns a hostname to this client. Note that DHCPv6 allows for a single client to lease multiple addresses and multiple prefixes at the same time. Therefore ip-addresses and prefixes are plural and are actually arrays. When the client sends multiple IA options (IA_NA or IA_PD), each reserved address or prefix is assigned to an individual IA of the appropriate type. If the number of IAs of specific type is lower than the number of reservations of that type, the number of reserved addresses or prefixes assigned to the client is equal to the number of IA_NAs or IA_PDs sent by the client, i.e. some reserved addresses or prefixes are not assigned. However, they still remain reserved for this client and the server will not assign them to any other client. If the number of IAs of specific type sent by the client is greater than the number of reserved addresses or prefixes, the server will try to assign all reserved addresses or prefixes to the individual IAs and dynamically allocate addresses or prefixes to remaining IAs. If the server cannot assign a reserved address or prefix because it is in use, the server will select the next reserved address or prefix and try to assign it to the client. If the server subsequently finds that there are no more reservations that can be assigned to the client at the moment, the server will try to assign leases dynamically. Making a reservation for a mobile host that may visit multiple subnets requires a separate host definition in each subnet it is expected to visit. It is not allowed to define multiple host definitions with the same hardware address in a single subnet. Multiple host definitions with the same hardware address are valid if each is in a different subnet. The reservation for a given host should include only one identifier, either DUID or hardware address. Defining both for the same host is considered a configuration error, but as of 1.1.0, it is not rejected. Adding host reservation incurs a performance penalty. In principle, when a server that does not support host reservation responds to a query, it needs to check whether there is a lease for a given address being considered for allocation or renewal. The server that also supports host reservation, has to perform additional checks: not only if the address is currently used (i.e. if there is a lease for it), but also whether the address could be used by someone else (i.e. if there is a reservation for it). That additional check incurs additional overhead.
Address/Prefix Reservation Types In a typical scenario there is an IPv6 subnet defined with a certain part of it dedicated for dynamic address allocation by the DHCPv6 server. There may be an additional address space defined for prefix delegation. Those dynamic parts are referred to as dynamic pools, address and prefix pools or simply pools. In principle, the host reservation can reserve any address or prefix that belongs to the subnet. The reservations that specify an address that belongs to configured pools are called "in-pool reservations". In contrast, those that do not belong to dynamic pools are called "out-of-pool reservations". There is no formal difference in the reservation syntax and both reservation types are handled uniformly. However, upcoming releases may offer improved performance if there are only out-of-pool reservations as the server will be able to skip reservation checks when dealing with existing leases. Therefore, system administrators are encouraged to use out-of-pool reservations if possible.
Conflicts in DHCPv6 Reservations As reservations and lease information are stored separately, conflicts may arise. Consider the following series of events. The server has configured the dynamic pool of addresses from the range of 2001:db8::10 to 2001:db8::20. Host A requests an address and gets 2001:db8::10. Now the system administrator decides to reserve address 2001:db8::10 for Host B. In general, reserving an address that is currently assigned to someone else is not recommended, but there are valid use cases where such an operation is warranted. The server now has a conflict to resolve. Let's analyze the situation here. If Host B boots up and request an address, the server is not able to assign the reserved address 2001:db8::10. A naive approach would to be immediately remove the lease for Host A and create a new one for Host B. That would not solve the problem, though, because as soon as Host B get the address, it will detect that the address is already in use by someone else (Host A) and would send a Decline message. Therefore in this situation, the server has to temporarily assign a different address from the dynamic pool (not matching what has been reserved) to Host B. When Host A renews its address, the server will discover that the address being renewed is now reserved for someone else (Host B). Therefore the server will remove the lease for 2001:db8::10, select a new address and create a new lease for it. It will send two addresses in its response: the old address with lifetime set to 0 to explicitly indicate that it is no longer valid and the new address with a non-zero lifetime. When Host B renews its temporarily assigned address, the server will detect that the existing lease does not match reservation, so it will release the current address Host B has and will create a new lease matching the reservation. Similar as before, the server will send two addresses: the temporarily assigned one with zeroed lifetimes, and the new one that matches reservation with proper lifetimes set. This recovery will succeed, even if other hosts will attempt to get the reserved address. Had Host C requested address 2001:db8::10 after the reservation was made, the server will propose a different address. This recovery mechanism allows the server to fully recover from a case where reservations conflict with existing leases. This procedure takes time and will roughly take as long as renew-timer value specified. The best way to avoid such recovery is to not define new reservations that conflict with existing leases. Another recommendation is to use out-of-pool reservations. If the reserved address does not belong to a pool, there is no way that other clients could get this address.
Reserving a Hostname When the reservation for the client includes the hostname, the server will assign this hostname to the client and send it back in the Client FQDN, if the client sent the FQDN option to the server. The reserved hostname always takes precedence over the hostname supplied by the client (via the FQDN option) or the autogenerated (from the IPv6 address) hostname. The server qualifies the reserved hostname with the value of the qualifying-suffix parameter. For example, the following subnet configuration: "subnet6": [ { "subnet": "2001:db8:1::/48", "pools": [ { "pool": "2001:db8:1::/80" } ], "reservations": [ { "duid": "01:02:03:04:05:0A:0B:0C:0D:0E", "ip-addresses": [ "2001:db8:1::100" ] "hostname": "alice-laptop" } ] } ], "dhcp-ddns": { "enable-updates": true, "qualifying-suffix": "example.isc.org." } will result in assigning the "alice-laptop.example.isc.org." hostname to the client using the DUID "01:02:03:04:05:0A:0B:0C:0D:0E". If the qualifying-suffix is not specified, the default (empty) value will be used, and in this case the value specified as a hostname will be treated as fully qualified name. Thus, by leaving the qualifying-suffix empty it is possible to qualify hostnames for the different clients with different domain names: "subnet6": [ { "subnet": "2001:db8:1::/48", "pools": [ { "pool": "2001:db8:1::/80" } ], "reservations": [ { "duid": "01:02:03:04:05:0A:0B:0C:0D:0E", "ip-addresses": [ "2001:db8:1::100" ] "hostname": "mark-desktop.example.org." } ] } ], "dhcp-ddns": { "enable-updates": true, } The above example results in the assignment of the "mark-desktop.example.org." hostname to the client using the DUID "01:02:03:04:05:0A:0B:0C:0D:0E".
Including Specific DHCPv6 Options in Reservations Kea 1.1.0 introduced the ability to specify options on a per host basis. The options follow the same rules as any other options. These can be standard options (see ), custom options (see ) or vendor specific options (see ). The following example demonstrates how standard options can be defined. "reservations": [ { "duid": "01:02:03:05:06:07:08", "ip-addresses": [ "2001:db8:1::2" ], "option-data": [ { "option-data": [ { "name": "dns-servers", "data": "3000:1::234" }, { "name": "nis-servers", "data": "3000:1::234" } } ] } ] Vendor specific options can be reserved in a similar manner: "reservations": [ { "duid": "aa:bb:cc:dd:ee:ff", "ip-addresses": [ "2001:db8::1" ], "option-data": [ { "name": "vendor-opts", "data": 4491" }, { "name": "tftp-servers", "space": "vendor-4491", "data": "3000:1::234" } ] } ] Options defined on host level have the highest priority. In other words, if there are options defined with the same type on global, subnet, class and host level, the host specific values will be used.
Reserving Client Classes in DHCPv6 The explains how to configure the server to assign classes to a client based on the content of the options that this client sends to the server. Host reservations mechanisms also allow for the static assignment of classes to clients. The definitions of these classes are placed in the Kea configuration. The following configuration snippet shows how to specify that the client belongs to classes reserved-class1 and reserved-class2. Those classes are associated with specific options being sent to the clients which belong to them. { "client-classes": [ { "name": "reserved-class1", "option-data": [ { "name": "dns-servers", "data": "2001:db8:1::50" } ] }, { "name": "reserved-class2", "option-data": [ { "name": "nis-servers", "data": "2001:db8:1::100" } ] } ], "subnet6": [ { "pools": [ { "pool": "2001:db8:1::/64" } ], "subnet": "2001:db8:1::/48", "reservations": [ { "duid": "01:02:03:04:05:06:07:08", "client-classes": [ "reserved-class1", "reserved-class2" ] } ] } ] } Static class assignments, as shown above, can be used in conjuction with classification using expressions.
Storing Host Reservations in MySQL or PostgreSQL It is possible to store host reservations in MySQL or PostgreSQL. See for information on how to configure Kea to use reservations stored in MySQL or PostgreSQL. Kea does not provide any dedicated tools for managing reservations in a database. The Kea wiki provides detailed information and examples of how reservations can be inserted into the database. In Kea 1.1.0 maximum length of an option specified per host is arbitrarily set to 4096 bytes.
Storing Host Reservations in CQL (Cassandra) Kea currently does not support storing reservations in Cassandra (CQL).
Fine Tuning DHCPv6 Host Reservation The host reservation capability introduces additional restrictions for the allocation engine (the component of Kea that selects an address for a client) during lease selection and renewal. In particular, three major checks are necessary. First, when selecting a new lease, it is not sufficient for a candidate lease to not be used by another DHCP client. It also must not be reserved for another client. Second, when renewing a lease, additional check must be performed whether the address being renewed is not reserved for another client. Finally, when a host renews an address or a prefix, the server has to check whether there is a reservation for this host, so the existing (dynamically allocated) address should be revoked and the reserved one be used instead. Some of those checks may be unnecessary in certain deployments and not performing them may improve performance. The Kea server provides the reservation-mode configuration parameter to select the types of reservations allowed for the particular subnet. Each reservation type has different constraints for the checks to be performed by the server when allocating or renewing a lease for the client. Allowed values are: all - enables all host reservation types. This is the default value. This setting is the safest and the most flexible. It allows in-pool and out-of-pool reservations. As all checks are conducted, it is also the slowest. out-of-pool - allows only out of pool host reservations. With this setting in place, the server may assume that all host reservations are for addresses that do not belong to the dynamic pool. Therefore it can skip the reservation checks when dealing with in-pool addresses, thus improving performance. Do not use this mode if any of your reservations use in-pool address. Caution is advised when using this setting. Kea 1.1.0 does not sanity check the reservations against reservation-mode and misconfiguration may cause problems. disabled - host reservation support is disabled. As there are no reservations, the server will skip all checks. Any reservations defined will be completely ignored. As the checks are skipped, the server may operate faster in this mode. An example configuration that disables reservation looks like follows: "Dhcp6": { "subnet6": [ { "subnet": "2001:db8:1::/64", "reservation-mode": "disabled", ... } ] } Another aspect of the host reservations are different types of identifiers. Kea 1.1.0 supports two types of identifiers in DHCPv6: hw-address and duid, but more identifier types are likely to be added in the future. This is beneficial from a usability perspective. However, there is a drawback. For each incoming packet Kea has to to extract each identifier type and then query the database to see if there is a reservation done by this particular identifier. If nothing is found, the next identifier is extracted and next query is issued. This process continues until either a reservation is found or all identifier types have been checked. Over time with an increasing number of supported identifier types, Kea would become slower and slower. To address this problem, a parameter called host-reservation-identifiers has been introduced. It takes a list of identifier types as a parameter. Kea will check only those identifier types enumerated in host-reservation-identifiers. From a performance perspective the number of identifier types should be kept to minimum, ideally limited to one. If your deployment uses several reservation types, please enumerate them from most to least frequently used as this increases the chances of Kea finding the reservation using the fewest number of queries. An example of host reservation identifiers looks as follows: "host-reservation-identifiers": [ "duid", "hw-address" ], "subnet6": [ { "subnet": "2001:db8:1::/64", ... } ] If not specified, the default value is: "host-reservation-identifiers": [ "hw-address", "duid" ]
Server Identifier in DHCPv6 The DHCPv6 protocol uses a "server identifier" (also known as a DUID) for clients to be able to discriminate between several servers present on the same link. RFC 3315 defines three DUID types: DUID-LLT, DUID-EN and DUID-LL. RFC 6355 also defines DUID-UUID. Future specifications may introduce new DUID types. The Kea DHCPv6 server generates a server identifier once, upon the first startup, and stores it in a file. This identifier isn't modified across restarts of the server and so is a stable identifier. Kea follows recommendation from RFC 3315 to use DUID-LLT as the default server identifier. However, we have received reports that some deployments require different DUID types, and there is a need to administratively select both DUID type and/or its contents. The server identifier can be configured using parameters within the server-id map element in the global scope of the Kea configuration file. The following example demonstrates how to select DUID-EN as a server identifier: "Dhcp6": { "server-id": { "type": "EN" }, ... } Currently supported values for type parameter are: "LLT", "EN" and "LL", for DUID-LLT, DUID-EN and DUID-LL respectively. When a new DUID type is selected the server will generate its value and replace any existing DUID in the file. The server will then use the new server identifier in all future interactions with the clients. If the new server identifier is created after some clients have obtained their leases, the clients using the old identifier will not be able to renew the leases: the server will ignore messages containing the old server identifier. Clients will continue sending Renew until they transition to the rebinding state. In this state they will start sending Rebind messages to multicast address without a server identifier. The server will respond to the Rebind messages with a new server identifier and the clients will associate the new server identifier with their leases. Although the clients will be able to keep their leases and will eventually learn the new server identifier, this will be at the cost of increased number of renewals and multicast traffic due to a need to rebind. Therefore it is recommended that modification of the server identifier type and value is avoided if the server has already assigned leases and these leases are still valid. There are cases when an administrator needs to explicitly specify a DUID value rather than allow the server to generate it. The following example demonstrates how to explicitly set all components of a DUID-LLT. "Dhcp6": { "server-id": { "type": "LLT", "htype": 8, "identifier": "A65DC7410F05", "time": 2518920166 }, ... } where: htype is a 16-bit unsigned value specifying hardware type, identifier is a link layer address, specified as a string of hexadecimal digits, time is a 32-bit unsigned time value. The hexadecimal representation of the DUID generated as a result of the configuration specified above will be: 00:01:00:08:96:23:AB:E6:A6:5D:C7:41:0F:05 |type |htype| time | identifier | It is allowed to use special value of 0 for "htype" and "time", which indicates that the server should use ANY value for these components. If the server already uses a DUID-LLT it will use the values from this DUID. If the server uses a DUID of a different type or doesn't use any DUID yet, it will generate these values. Similarly, if the "identifier" is assigned an empty string, the value of the identifier will be generated. Omitting any of these parameters is equivalent to setting them to those special values. For example, the following configuration: "Dhcp6": { "server-id": { "type": "LLT", "htype": 0, "identifier": "", "time": 2518920166 }, ... } indicates that the server should use ANY link layer address and hardware type. If the server is already using DUID-LLT it will use the link layer address and hardware type from the existing DUID. If the server is not using any DUID yet, it will use link layer address and hardware type from one of the available network interfaces. The server will use an explicit value of time. If it is different than a time value present in the currently used DUID, that value will be replaced, effectively causing modification of the current server identifier. The following example demonstrates an explicit configuration of a DUID-EN: "Dhcp6": { "server-id": { "type": "EN", "enterprise-id": 2495, "identifier": "87ABEF7A5BB545" }, ... } where: enterprise-id is a 32-bit unsigned value holding enterprise number, identifier is a variable length identifier within DUID-EN. The hexadecimal representation of the DUID-EN created according to the configuration above is: 00:02:00:00:09:BF:87:AB:EF:7A:5B:B5:45 |type | ent-id | identifier | As in the case of the DUID-LLT, special values can be used for the configuration of the DUID-EN. If enterprise-id is 0, the server will use a value from the existing DUID-EN. If the server is not using any DUID or the existing DUID has a different type, the ISC enterprise id will be used. When an empty string is used for identifier, the identifier from the existing DUID-EN will be used. If the server is not using any DUID-EN the new 6-bytes long identifier will be generated. DUID-LL is configured in the same way as DUID-LLT with an exception that the time parameter has no effect for DUID-LL, because this DUID type only comprises a hardware type and link layer address. The following example demonstrates how to configure DUID-LL: "Dhcp6": { "server-id": { "type": "LL", "htype": 8, "identifier": "A65DC7410F05" }, ... } which will result in the following server identifier: 00:03:00:08:A6:5D:C7:41:0F:05 |type |htype| identifier | The server stores the generated server identifier in the following location: [kea-install-dir]/var/kea/kea-dhcp6-serverid. In some uncommon deployments where no stable storage is available, the server should be configured not to try to store the server identifier. This choice is controlled by the value of persist boolean parameter: "Dhcp6": { "server-id": { "type": "EN", "enterprise-id": 2495, "identifier": "87ABEF7A5BB545", "persist": false }, ... } The default value of the "persist" parameter is true which configures the server to store the server identifier on a disk. In the example above, the server is configured to not store the generated server identifier on a disk. But, if the server identifier is not modified in the configuration the same value will be used after server restart, because entire server identifier is explicitly specified in the configuration.
Stateless DHCPv6 (Information-Request Message) Typically DHCPv6 is used to assign both addresses and options. These assignments (leases) have state that changes over time, hence their name, stateful. DHCPv6 also supports a stateless mode, where clients request configuration options only. This mode is considered lightweight from the server perspective as it does not require any state tracking; hence its name. The Kea server supports stateless mode. Clients can send Information-Request messages and the server will send back answers with the requested options (providing the options are available in the server configuration). The server will attempt to use per-subnet options first. If that fails - for whatever reason - it will then try to provide options defined in the global scope. Stateless and stateful mode can be used together. No special configuration directives are required to handle this. Simply use the configuration for stateful clients and the stateless clients will get just options they requested. This usage of global options allows for an interesting case. It is possible to run a server that provides just options and no addresses or prefixes. If the options have the same value in each subnet, the configuration can define required options in the global scope and skip subnet definitions altogether. Here's a simple example of such a configuration: "Dhcp6": { "interfaces-config": { "interfaces": [ "ethX" ] }, "option-data": [ { "name": "dns-servers", "data": "2001:db8::1, 2001:db8::2" } ], "lease-database": { "type": "memfile" } } This very simple configuration will provide DNS server information to all clients in the network, regardless of their location. Note the specification of the memfile lease database: this is needed as Kea requires a lease database to be specified even if it is not used.
Support for RFC 7550 The RFC 7550 introduced some changes to the DHCPv6 protocol to resolve a few issues with the coexistence of multiple stateful options in the messages sent between the clients and servers. The typical example is when the client, such as a requesting router, requests an allocation of both addresses and prefixes when it performs the 4-way (SARR) exchange with the server. If the server is not configured to allocate any prefixes but it can allocate some addresses, it will respond with the IA_NA(s) containing allocated addresses and the IA_PD(s) containing the NoPrefixAvail status code. If the client can operate without prefixes it may transition to the 'bound' state when it sends Renew/Rebind messages to the server, according to the T1 and T2 times, to extend the lifetimes of the allocated addresses. If the client is still interested in obtaining prefixes from the server it may also include an IA_PD in the Renew/Rebind to request allocation of the prefixes. If the server still cannot allocate the prefixes, it will respond with the IA_PD(s) containing NoPrefixAvail status code. However, if the server can now allocate the prefixes it will do so, and send them in the IA_PD(s) to the client. Allocation of leases during the Renew/Rebind was not supported in the RFC 3315 and RFC 3633, and has been introduced in RFC 7550. Kea supports this new behavior and it doesn't provide any configuration mechanisms to disable it. The following are the other behaviors specified in the RFC 7550 supported by the Kea DHCPv6 server: Set T1/T2 timers to the same value for all stateful (IA_NA and IA_PD) options to facilitate renewal of all client's leases at the same time (in a single message exchange), NoAddrsAvail and NoPrefixAvail status codes are placed in the IA_NA and IA_PD options in the Advertise message, rather than as the top level options.
Using Specific Relay Agent for a Subnet The relay has to have an interface connected to the link on which the clients are being configured. Typically the relay has a global IPv6 address configured on the interface that belongs to the subnet from which the server will assign addresses. In the typical case, the server is able to use the IPv6 address inserted by the relay (in the link-addr field in RELAY-FORW message) to select the appropriate subnet. However, that is not always the case. The relay address may not match the subnet in certain deployments. This usually means that there is more than one subnet allocated for a given link. The two most common examples where this is the case are long lasting network renumbering (where both old and new address space is still being used) and a cable network. In a cable network both cable modems and the devices behind them are physically connected to the same link, yet they use distinct addressing. In such case, the DHCPv6 server needs additional information (like the value of interface-id option or IPv6 address inserted in the link-addr field in RELAY-FORW message) to properly select an appropriate subnet. The following example assumes that there is a subnet 2001:db8:1::/64 that is accessible via a relay that uses 3000::1 as its IPv6 address. The server will be able to select this subnet for any incoming packets that came from a relay with an address in 2001:db8:1::/64 subnet. It will also select that subnet for a relay with address 3000::1. "Dhcp6": { "subnet6": [ { "subnet": "2001:db8:1::/64", "pools": [ { "pool": "2001:db8:1::1-2001:db8:1::ffff" } ], "relay": { "ip-address": "3000::1" } } ] }
Segregating IPv6 Clients in a Cable Network In certain cases, it is useful to mix relay address information, introduced in with client classification, explained in . One specific example is a cable network, where typically modems get addresses from a different subnet than all devices connected behind them. Let's assume that there is one CMTS (Cable Modem Termination System) with one CM MAC (a physical link that modems are connected to). We want the modems to get addresses from the 3000::/64 subnet, while everything connected behind modems should get addresses from another subnet (2001:db8:1::/64). The CMTS that acts as a relay an uses address 3000::1. The following configuration can serve that configuration: "Dhcp6": { "subnet6": [ { "subnet": "3000::/64", "pools": [ { "pool": "3000::2 - 3000::ffff" } ], "client-class": "VENDOR_CLASS_docsis3.0", "relay": { "ip-address": "3000::1" } }, { "subnet": "2001:db8:1::/64", "pools": [ { "pool": "2001:db8:1::1-2001:db8:1::ffff" } ], "relay": { "ip-address": "3000::1" } } ] }
MAC/Hardware Addresses in DHCPv6 MAC/hardware addresses are available in DHCPv4 messages from the clients and administrators frequently use that information to perform certain tasks, like per host configuration, address reservation for specific MAC addresses and other. Unfortunately, the DHCPv6 protocol does not provide any completely reliable way to retrieve that information. To mitigate that issue a number of mechanisms have been implemented in Kea that attempt to gather it. Each of those mechanisms works in certain cases, but may fail in other cases. Whether the mechanism works or not in the particular deployment is somewhat dependent on the network topology and the technologies used. Kea allows configuration of which of the supported methods should be used and in what order. This configuration may be considered a fine tuning of the DHCP deployment. In a typical deployment the default value of "any" is sufficient and there is no need to select specific methods. Changing the value of this parameter is the most useful in cases when an administrator wants to disable certain method, e.g. if the administrator trusts the network infrastructure more than the information provided by the clients themselves, the administrator may prefer information provided by the relays over that provided by the clients. The configuration is controlled by the mac-sourcesparameter as follows: "Dhcp6": { "mac-sources": [ "method1", "method2", "method3", ... ], "subnet6": [ ... ], ... } When not specified, a special value of "any" is used, which instructs the server to attempt to use all the methods in sequence and use value returned by the first one that succeeds. Supported methods are: any - Not an actual method, just a keyword that instructs Kea to try all other methods and use the first one that succeeds. This is the default operation if no mac-sources are defined. raw - In principle, a DHCPv6 server could use raw sockets to receive incoming traffic and extract MAC/hardware address information. This is currently not implemented for DHCPv6 and this value has no effect. duid - DHCPv6 uses DUID identifiers instead of MAC addresses. There are currently four DUID types defined, with two of them (DUID-LLT, which is the default one and DUID-LL) convey MAC address information. Although RFC 3315 forbids it, it is possible to parse those DUIDs and extract necessary information from them. This method is not completely reliable, as clients may use other DUID types, namely DUID-EN or DUID-UUID. ipv6-link-local - Another possible acquisition method comes from the source IPv6 address. In typical usage, clients are sending their packets from IPv6 link-local addresses. There is a good chance that those addresses are based on EUI-64, which contains MAC address. This method is not completely reliable, as clients may use other link-local address types. In particular, privacy extensions, defined in RFC 4941, do not use MAC addresses. Also note that successful extraction requires that the address's u-bit must be set to 1 and its g-bit set to 0, indicating that it is an interface identifier as per RFC 2373, section 2.5.1. client-link-addr-option - One extension defined to alleviate missing MAC issues is client link-layer address option, defined in RFC 6939. This is an option that is inserted by a relay and contains information about client's MAC address. This method requires a relay agent that supports the option and is configured to insert it. This method is useless for directly connected clients. This parameter can also be specified as rfc6939, which is an alias for client-link-addr-option. remote-id - RFC 4649 defines a remote-id option that is inserted by a relay agent. Depending on the relay agent configuration, the inserted option may convey the client's MAC address information. This parameter can also be specified as rfc4649, which is an alias for remote-id. subscriber-id - Another option that is somewhat similar to the previous one is subscriber-id, defined in RFC 4580. It is, too, inserted by a relay agent that is configured to insert it. This parameter can also be specified as rfc4580, which is an alias for subscriber-id. This method is currently not implemented. docsis-cmts - Yet another possible source of MAC address information are the DOCSIS options inserted by a CMTS that acts as a DHCPv6 relay agent in cable networks. This method attempts to extract MAC address information from suboption 1026 (cm mac) of the vendor specific option with vendor-id=4491. This vendor option is extracted from the relay-forward message, not the original client's message. docsis-modem - Yet another possible source of MAC address information are the DOCSIS options inserted by the cable modem itself. This method attempts to extract MAC address information from suboption 36 (device id) of the vendor specific option with vendor-id=4491. This vendor option is extracted from the original client's message, not from any relay options.
Duplicate Addresses (DECLINE Support) The DHCPv6 server is configured with a certain pool of addresses that it is expected to hand out to the DHCPv6 clients. It is assumed that the server is authoritative and has complete jurisdiction over those addresses. However, due to various reasons, such as misconfiguration or a faulty client implementation that retains its address beyond the valid lifetime, there may be devices connected that use those addresses without the server's approval or knowledge. Such an unwelcome event can be detected by legitimate clients (using Duplicate Address Detection) and reported to the DHCPv6 server using a DECLINE message. The server will do a sanity check (if the client declining an address really was supposed to use it), then will conduct a clean up operation and confirm it by sending back a REPLY message. Any DNS entries related to that address will be removed, the fact will be logged and hooks will be triggered. After that is done, the address will be marked as declined (which indicates that it is used by an unknown entity and thus not available for assignment to anyone) and a probation time will be set on it. Unless otherwise configured, the probation period lasts 24 hours. After that period, the server will recover the lease (i.e. put it back into the available state) and the address will be available for assignment again. It should be noted that if the underlying issue of a misconfigured device is not resolved, the duplicate address scenario will repeat. On the other hand, it provides an opportunity to recover from such an event automatically, without any sysadmin intervention. To configure the decline probation period to a value other than the default, the following syntax can be used: "Dhcp6": { "decline-probation-period": 3600, "subnet6": [ ... ], ... } The parameter is expressed in seconds, so the example above will instruct the server to recycle declined leases after an hour. There are several statistics and hook points associated with the Decline handling procedure. The lease6_decline hook is triggered after the incoming Decline message has been sanitized and the server is about to decline the lease. The declined-addresses statistic is increased after the hook returns (both global and subnet specific variants). (See and for more details on DHCPv4 statistics and Kea hook points.) Once the probation time elapses, the declined lease is recovered using the standard expired lease reclamation procedure, with several additional steps. In particular, both declined-addresses statistics (global and subnet specific) are decreased. At the same time, reclaimed-declined-addresses statistics (again in two variants, global and subnet specific) are increased. Note about statistics: The server does not decrease the assigned-addresses statistics when a DECLINE message is received and processed successfully. While technically a declined address is no longer assigned, the primary usage of the assigned-addresses statistic is to monitor pool utilization. Most people would forget to include declined-addresses in the calculation, and simply do assigned-addresses/total-addresses. This would have a bias towards under-representing pool utilization. As this has a potential for major issues, we decided not to decrease assigned addresses immediately after receiving Decline, but to do it later when we recover the address back to the available pool.
Statistics in the DHCPv6 Server This section describes DHCPv6-specific statistics. For a general overview and usage of statistics, see . The DHCPv6 server supports the following statistics: DHCPv6 Statistics Statistic Data Type Description pkt6-received integer Number of DHCPv6 packets received. This includes all packets: valid, bogus, corrupted, rejected etc. This statistic is expected to grow rapidly. pkt6-receive-drop integer Number of incoming packets that were dropped. The exact reason for dropping packets is logged, but the most common reasons may be: an unacceptable or not supported packet type, direct responses are forbidden, the server-id sent by the client does not match the server's server-id or the packet is malformed. pkt6-parse-failed integer Number of incoming packets that could not be parsed. A non-zero value of this statistic indicates that the server received a malformed or truncated packet. This may indicate problems in your network, faulty clients, faulty relay agents or a bug in the server. pkt6-solicit-received integer Number of SOLICIT packets received. This statistic is expected to grow. Its increase means that clients that just booted started their configuration process and their initial packets reached your server. pkt6-advertise-received integer Number of ADVERTISE packets received. Advertise packets are sent by the server and the server is never expected to receive them. A non-zero value of this statistic indicates an error occurring in the network. One likely cause would be a misbehaving relay agent that incorrectly forwards ADVERTISE messages towards the server rather back to the clients. pkt6-request-received integer Number of REQUEST packets received. This statistic is expected to grow. Its increase means that clients that just booted received the server's response (ADVERTISE), accepted it and are now requesting an address (REQUEST). pkt6-reply-received integer Number of REPLY packets received. This statistic is expected to remain zero at all times, as REPLY packets are sent by the server and the server is never expected to receive them. A non-zero value indicates an error. One likely cause would be a misbehaving relay agent that incorrectly forwards REPLY messages towards the server, rather back to the clients. pkt6-renew-received integer Number of RENEW packets received. This statistic is expected to grow. Its increase means that clients received their addresses and prefixes and are trying to renew them. pkt6-rebind-received integer Number of REBIND packets received. A non-zero value indicates that clients didn't receive responses to their RENEW messages (regular lease renewal mechanism) and are attempting to find any server that is able to take over their leases. It may mean that some server's REPLY messages never reached the clients. pkt6-release-received integer Number of RELEASE packets received. This statistic is expected to grow when a device is being shut down in the network. It indicates that the address or prefix assigned is reported as no longer needed. Note that many devices, especially wireless, do not send RELEASE packets either because of design choice or due to the client moving out of range. pkt6-decline-received integer Number of DECLINE packets received. This statistic is expected to remain close to zero. Its increase means that a client leased an address, but discovered that the address is currently used by an unknown device in your network. If this statistic is growing, it may indicate a misconfigured server or devices that have statically assigned conflicting addresses. pkt6-infrequest-received integer Number of INFORMATION-REQUEST packets received. This statistic is expected to grow if there are devices that are using stateless DHCPv6. INFORMATION-REQUEST messages are used by clients that request stateless configuration, i.e. options and parameters other than addresses or prefixes. pkt6-dhcpv4-query-received integer Number of DHCPv4-QUERY packets received. This statistic is expected to grow if there are devices that are using DHCPv4-over-DHCPv6. DHCPv4-QUERY messages are used by DHCPv4 clients on an IPv6 only line which encapsulatesi the requests over DHCPv6. pkt6-dhcpv4-response-received integer Number of DHCPv4-RESPONSE packets received. This statistic is expected to remain zero at all times, as DHCPv4-RESPONSE packets are sent by the server and the server is never expected to receive them. A non-zero value indicates an error. One likely cause would be a misbehaving relay agent that incorrectly forwards DHCPv4-RESPONSE message towards the server rather back to the clients. pkt6-unknown-received integer Number of packets received of an unknown type. A non-zero value of this statistic indicates that the server received a packet that it wasn't able to recognize: either it had an unsupported type or was possibly malformed. pkt6-sent integer Number of DHCPv6 packets sent. This statistic is expected to grow every time the server transmits a packet. In general, it should roughly match pkt6-received, as most incoming packets cause the server to respond. There are exceptions (e.g. server receiving a REQUEST with server-id matching other server), so do not worry, if it is lesser than pkt6-received. pkt6-advertise-sent integer Number of ADVERTISE packets sent. This statistic is expected to grow in most cases after a SOLICIT is processed. There are certain uncommon, but valid cases where incoming SOLICIT is dropped, but in general this statistic is expected to be close to pkt6-solicit-received. pkt6-reply-sent integer Number of REPLY packets sent. This statistic is expected to grow in most cases after a SOLICIT (with rapid-commit), REQUEST, RENEW, REBIND, RELEASE, DECLINE or INFORMATION-REQUEST is processed. There are certain cases where there is no response. pkt6-dhcpv4-response-sent integer Number of DHCPv4-RESPONSE packets sent. This statistic is expected to grow in most cases after a DHCPv4-QUERY is processed. There are certain cases where there is no response. subnet[id].total-nas integer This statistic shows the total number of NA addresses available for DHCPv6 management for a given subnet. In other words, this is the sum of all addresses in all configured pools. This statistic changes only during configuration changes. Note that it does not take into account any addresses that may be reserved due to host reservation. The id is the subnet-id of a given subnet. This statistic is exposed for each subnet separately and is reset during a reconfiguration event. subnet[id].assigned-nas integer This statistic shows the number of NA addresses in a given subnet that are assigned. This statistic increases every time a new lease is allocated (as a result of receiving a REQUEST message) and is decreased every time a lease is released (a RELEASE message is received) or expires. The id is the subnet-id of a given subnet. This statistic is exposed for each subnet separately and is reset during a reconfiguration event. subnet[id].total-pds integer This statistic shows the total number of PD prefixes available for DHCPv6 management for a given subnet. In other words, this is the sum of all prefixes in all configured pools. This statistic changes only during configuration changes. Note it does not take into account any prefixes that may be reserved due to host reservation. The id is the subnet-id of a given subnet. This statistic is exposed for each subnet separately and is reset during a reconfiguration event. subnet[id].assigned-pds integer This statistic shows the number of PD prefixes in a given subnet that are assigned. This statistic increases every time a new lease is allocated (as a result of receiving a REQUEST message) and is decreased every time a lease is released (a RELEASE message is received) or expires. The id is the subnet-id of a given subnet. This statistic is exposed for each subnet separately and is reset during a reconfiguration event. declined-addresses integer This statistic shows the number of IPv6 addresses that are currently declined and so counts the number of leases currently unavailable. Once a lease is recovered, this statistic will be decreased. Ideally, this statistic should be zero. If this statistic is non-zero (or worse, increasing), the network administrator should investigate if there is a misbehaving device in the network. This is a global statistic that covers all subnets. subnet[id].declined-addresses integer This statistic shows the number of IPv6 addresses that are currently declined in a given subnet. This statistic counts the number of leases currently unavailable. Once a lease is recovered, this statistic will be decreased. Ideally, this statistic should be zero. If this statistic is non-zero (or worse, increasing), a network administrator should investigate if there is a misbehaving device in the network. The id is the subnet-id of a given subnet. This statistic is exposed for each subnet separately. reclaimed-declined-addresses integer This statistic shows the number of IPv6 addresses that were declined, but have now been recovered. Unlike declined-addresses, this statistic never decreases. It can be used as a long term indicator of how many actual valid Declines were processed and recovered from. This is a global statistic that covers all subnets. subnet[id].reclaimed-declined-addresses integer This statistic shows the number of IPv6 addresses that were declined, but have now been recovered. Unlike declined-addresses, this statistic never decreases. It can be used as a long term indicator of how many actual valid Declines were processed and recovered from. The id is the subnet-id of a given subnet. This statistic is exposed for each subnet separately.
Management API for the DHCPv6 Server The management API allows the issuing of specific management commands, such as statistics retrieval, reconfiguration or shutdown. For more details, see . Currently the only supported communication channel type is UNIX stream socket. By default there are no sockets open. To instruct Kea to open a socket, the following entry in the configuration file can be used: "Dhcp6": { "control-socket": { "socket-type": "unix", "socket-name": "/path/to/the/unix/socket" }, "subnet6": [ ... ], ... } The length of the path specified by the socket-name parameter is restricted by the maximum length for the unix socket name on your operating system, i.e. the size of the sun_path field in the sockaddr_un structure, decreased by 1. This value varies on different operating systems between 91 and 107 characters. Typical values are 107 on Linux and 103 on FreeBSD. Communication over control channel is conducted using JSON structures. See the Control Channel section in the Kea Developer's Guide for more details. The DHCPv6 server supports statistic-get, statistic-reset, statistic-remove, statistic-get-all, statistic-reset-all and statistic-remove-all, specified in . It also supports list-commands and shutdown, specified in and , respectively.
Supported DHCPv6 Standards The following standards are currently supported: Dynamic Host Configuration Protocol for IPv6, RFC 3315: Supported messages are SOLICIT, ADVERTISE, REQUEST, RELEASE, RENEW, REBIND, INFORMATION-REQUEST, CONFIRM and REPLY. IPv6 Prefix Options for Dynamic Host Configuration Protocol (DHCP) version 6, RFC 3633: Supported options are IA_PD and IA_PREFIX. Also supported is the status code NoPrefixAvail. DNS Configuration options for Dynamic Host Configuration Protocol for IPv6 (DHCPv6), RFC 3646: Supported option is DNS_SERVERS. The Dynamic Host Configuration Protocol for IPv6 (DHCPv6) Relay Agent Remote-ID Option, RFC 4649: REMOTE-ID option is supported. The Dynamic Host Configuration Protocol for IPv6 (DHCPv6) Client Fully Qualified Domain Name (FQDN) Option, RFC 4704: Supported option is CLIENT_FQDN. Relay-Supplied DHCP Options, RFC 6422: Full functionality is supported: OPTION_RSOO, ability of the server to echo back the options, checks whether an option is RSOO-enabled, ability to mark additional options as RSOO-enabled. Client Link-Layer Address Option in DHCPv6, RFC 6939: Supported option is client link-layer address option. Issues and Recommendations with Multiple Stateful DHCPv6 Options, RFC 7550: All recommendations related to the DHCPv6 server operation are supported.
DHCPv6 Server Limitations These are the current limitations of the DHCPv6 server software. Most of them are reflections of the early stage of development and should be treated as not implemented yet, rather than actual limitations. The server will allocate, renew or rebind a maximum of one lease for a particular IA option (IA_NA or IA_PD) sent by a client. RFC 3315 and RFC 3633 allow for multiple addresses or prefixes to be allocated for a single IA. Temporary addresses are not supported. Client reconfiguration (RECONFIGURE) is not yet supported.
kea-1.1.0/doc/guide/config.xml0000664000175000017500000001133312772445242013037 00000000000000 ]> Kea Configuration Kea is designed to allow different methods by which it can be configured, each method being implemented by a component known as a configuration backend. At present, only one such backend is available, that allowing configuration by means of a JSON file.
JSON Configuration Backend JSON is the default configuration backend. It assumes that the servers are started from the command line (either directly or using a script, e.g. keactrl). The JSON backend uses certain signals to influence Kea. The configuration file is specified upon startup using the -c parameter.
JSON Syntax Configuration files for DHCPv4, DHCPv6 and DDNS modules are defined in an extended JSON format. Basic JSON is defined in RFC 4627. Kea components use a slightly modified form of JSON in that they allow shell-style comments in the file: lines with the hash (#) character in the first column are comment lines and are ignored. The configuration file consists of a single object (often colloquially called a map) started with a curly bracket. It comprises the "Dhcp4", "Dhcp6", "DhcpDdns" and/or "Logging" objects. It is possible to define additional elements, but they will be ignored. For example, it is possible to define Dhcp4, Dhcp6 and Logging elements in a single configuration file that can be used to start both the DHCPv4 and DHCPv6 components. When starting, the DHCPv4 component will use Dhcp4 object to configure itself and the Logging object to configure logging parameters; it will ignore the Dhcp6 object. A very simple configuration for both DHCPv4 and DHCPv6 could look like this: # The whole configuration starts here. { # DHCPv4 specific configuration starts here. "Dhcp4": { "interfaces-config": { "interfaces": [ "eth0" ], "dhcp-socket-type": "raw" }, "valid-lifetime": 4000, "renew-timer": 1000, "rebind-timer": 2000, "subnet4": [{ "pools": [ { "pool": "192.0.2.1-192.0.2.200" } ], "subnet": "192.0.2.0/24" }] }, # DHCPv4 specific configuration ends here. # DHCPv6 specific configuration starts here. "Dhcp6": { "interfaces-config": { "interfaces": [ "eth1" ] }, "preferred-lifetime": 3000, "valid-lifetime": 4000, "renew-timer": 1000, "rebind-timer": 2000, "subnet6": [{ "pools": [ { "pool": "2001:db8::/80" } ], "subnet": "2001:db8::/64" }] }, # DHCPv6 specific configuration ends here. # Logger parameters (that could be shared among several components) start here. # This section is used by both the DHCPv4 and DHCPv6 servers. "Logging": { "loggers": [{ "name": "*", "severity": "DEBUG" }] } # Logger parameters end here. # The whole configuration structure ends here. } More examples are available in the installed share/doc/kea/examples directory. To avoid repetition of mostly similar structures, examples in the rest of this guide will showcase only the subset of parameters appropriate for a given context. For example, when discussing the IPv6 subnets configuration in DHCPv6, only subnet6 parameters will be mentioned. It is implied that the remaining elements (the global map that holds Dhcp6, Logging and possibly DhcpDdns) are present, but they are omitted for clarity. Usually, locations where extra parameters may appear are denoted by an ellipsis.
Simplified Notation It is sometimes convenient to refer to a specific element in the configuration hierarchy. Each hierarchy level is separated by a slash. If there is an array, a specific instance within that array is referenced by a number in square brackets (with numbering starting at zero). For example, in the above configuration the valid-lifetime in the Dhcp6 component can be referred to as Dhcp6/valid-lifetime and the pool in the first subnet defined in the DHCPv6 configuration as Dhcp6/subnet6[0]/pool.
kea-1.1.0/doc/guide/faq.xml0000664000175000017500000001533412772445242012346 00000000000000 ]> Frequently Asked Questions This chapter contains a number of frequently asked questions and troubleshooting tips. It currently lacks content, but it is expected to grow over time.
General Frequently Asked Questions
Where did the Kea name came from? Kea is the name of a high mountain parrot living in New Zealand. See this for an extended answer.
Feature X is not supported yet. When/if will it be available? Kea is developed by a small team of engineers. Our resources are limited, so we need to prioritize requests. The complexity of a new feature (how difficult it is to implement a feature and how likely it would break something that already works), amount of work required and expected popularity (i.e., how many users would actually benefit from it) are three leading factors. We sometimes also have contractual obligations. Simply stating that you'd like feature X is useful. We try to implement features that are actively requested first, but the reality is that we have more requests than we can handle, so some of them must be postponed, at least in the near future. So is your request likely to be rejected? Not at all. You can do many things to greatly improve the chances of your request being fulfilled. First, it helps to explain why you need a feature. If your explanation is reasonable and there are likely other users that would benefit from it, the chances for Kea developers to put this task on a roadmap is better. Saying that you are willing to participate in tests (e.g., test engineering drops when they become available) is also helpful. Another thing you can do to greatly improve the chances of a feature to appear is to actually develop it on your own and submit a patch. That's an avenue that people often forget about. Kea is open source software and we do accept patches. There are certain requirements, like code quality, comments, unit-tests, documentation, etc., but we have accepted a significant number of patches in the past, so it's doable. Accepted contributions range from minor documentation corrections to significant new features, like support for a new database type. Before considering writing and submitting a patch, make sure you read the Contributor's Guide in the Kea Developer's Guide. Kea is developed by ISC, which is a non-profit organization. You may consider signing a development contract with us. In the past we did implement certain features due to contractual obligations. With additional funds we are able to put extra engineering efforts into Kea development. We can reshuffle our schedule or add extra hands to the team if needed. Please keep in mind that Kea is open source software and its principle goal is to provide a good DHCP solution that can be used by everyone. In other words, we may refuse a contract that would tie the solution to specific proprietary technology or make it unusable for other users. Also, we strive to make Kea a reference implementation, so if your proposal significantly violates a RFC, we may have a problem with that. Nevertheless, please talk to us and we may be able to find a solution. Finally, Kea has a public roadmap, with releases happening several times each year. We tend to not modify plans for the current milestone, unless there are very good reasons to do so. Therefore "I'd like a feature X in 6 months" is much better received than "I'd like a feature X now".
Frequently Asked Questions about DHCPv4
I set up a firewall, but the Kea server still receives the traffic. Why? Any DHCPv4 server must be able to receive from and send traffic to hosts that don't have an IPv4 address assigned yet. That is typically not possible with regular UDP sockets, therefore the Kea DHCPv4 server uses raw sockets by default. Raw sockets mean that the incoming packets are received as raw Ethernet frames, thus bypassing the whole kernel IP stack, including any firewalling rules your kernel may provide. If you do not want the server to use raw sockets, it is possible to configure the Kea DHCPv4 server to use UDP sockets instead. See dhcp-socket-type described in . However, using UDP sockets has certain limitations. In particular, they may not allow for sending responses directly to clients without IPv4 addresses assigned. That's ok, if all your traffic is coming through relay agents.
Frequently Asked Questions about DHCPv6
Kea DHCPv6 doesn't seem to get incoming traffic. I checked with tcpdump (or other traffic capture software) that the incoming traffic is reaching the box. What's wrong? Please check whether your OS has any IPv6 filtering rules. Many operating systems are shipped with firewalls that discard incoming IPv6 traffic by default. In particular, many Linux distributions do that. Please check the output of the following command: # ip6tables -L -n One common mistake in this area is to use iptables tool, which lists IPv4 firewall rules only.
kea-1.1.0/doc/guide/kea-logo-100x70.png0000664000175000017500000002337212772017075014116 00000000000000‰PNG  IHDRdF:†1iðiCCPICC Profile8UÝoÛT?‰o\¤? ±Ž‹¯US[¹­ÆI“¥éB¹ÍØ*¤ÉunS×6¶ÓmUŸöo ø€²xB Äö²í´ISAÕ$¤=tÚ@h“ö‚ªp®¯S»]Ƹ‘¯9çw>ïÑ5@ÇWšã˜I`Þò]5Ÿ‘Ÿ˜–;V! ÏA'ô@§¦{Nº\..Æ…GÖÃ_!ÁÞ7ÚëÿsuV©§$žBlW=}ñi€”©;® ÞFùð)ßAÜñ<â.&ˆXax–ã,Ã38Sê(b–‹¤×µ*â%Äý31ùl ó‚µ#O-êºÌzQvíšaÒXºOPÿÏ5o6Zñzñéòæ&â»Õ^wÇÔ®k¹IÄ/#¾æø&ñ½Æ\%x/@ò™š{¤ÂùÉ7ëSï Þ‰¸jø…©P¾hÍ”&¸mryÎ>ª†œkº7Š=ƒߪÓB‘ç#@•fs¬_ˆ{ë±Ð¿0î-LæZ~ë£%îGpßÓÆËˆ{èÚêÏYX¦f^åþ…+Ž_sÖ-³Tä>‰D½ Æ@îקƸ-9àã!r[2]3ŽBþ’c³ˆ¹‘ónC­„œš›Ës?ä>µ*¡ÏÔ®ª–e½D|Ž%4 `à î:X°2¨‡ ¾pQSL”PÔR”‰§aeíyå€ÃqĘ ¬×™5FiÏáî„›t…ìÇç )’Cd˜Œ€LÞ$o‘Ã$‹ÒrpÓ¶‹ÏbÝÙôó>4Ð+ãƒÌ¹žF_ï¬{ÒЯô÷kû‘œi+ŸxÀô˜ñú¯.ý°+ò±B.¼{³ëêL<©¿©Û©õÔ î«©µˆ‘ú=µ†¿UHcnfÑ<>F‡Ë ^Ãe||ÐpÿyvŒ·%bÍ:×iX'襇%8ÛI•ß”?•å å¼rw[—ÛvIøTøVøQøNø^ødá’pYøI¸"|#\ŒÕãçcóìƒz[Õ2M»^S0¥Œ´[zIÊJ/H¯HÅÈŸÔ- IcÒÔìÞ<·x¼x-œÀ½ÕÕö±8¯‚ZNxA‡-8³mþCkÒK†HaÛÔ³Yn1Äœ˜Ó ‹{ÅqHg¸•Ÿ¸u#¸ç¶Lþ˜ hŒ¯s ˜:6«Ìz!Ðy@}zÚgí¨íœqÙº/ïS”×å4~ª¨\°ôÁ~Y3M9Py²K=ê.Ðê °ï ¿¢¨Á÷-±óz$óß8ôÞY7"Ùtàk ûµHÖ‡wⳟ\8 7Ü…ðÎO$~ðjû÷ñ]¼›n5›ð¾êø`ããfóŸåfsãKô¿pÉüYqxµá†"ÅIDATxÝ\ `TÕ¹>ç.3“e&D­CBÐB©Uö¸ëS[y¾PÛ VÀ l_µv±]^µUPAªÕª,‚¶öÑjkõVk[Ü $PPÜpaK2If2sï=ïûν3 Äòz 3÷ž{Öÿû·óŸsGŠî—¤¨¦¨†Æ??U«ð„%¦g•!ã!ä)JȾRª^JÊ"©T‘†­”—R6¥ê… )ÞFÙZ)½:Çk}­yÑ›fšÄ·ü99yGõRÕÞ÷íÜ€È'òeÿfGÔY†0F©F*%K¥Å¦_Óó„"dJá/§1ÎJJàƒ þá¹rPÖU» %Ö¸Â[¡<÷™¦'þY›­ÀsûÎæá‹îÈ>@Ä*Ë{(˽Ô0ä„’çÉYH¢’ ‚¸ ®”®O'ªãŸ§?÷’Žà€ˆÿ€$a)Cš†”…Mµº)4û¬ë©Gâ‹jŸÖ™¾Ä&AûAîü:š€dT“–ˆheÿA†™ BN–!ëÒ@¥)ˆ¢JEK¦ŽÒG!¡.•ÐrÂØZ²¼”û7Cx?«_X÷[ݶ/-%Wî:Úm»êuxríêåÀ²4E——œ,òÌo€TSŒ0TÚ…ÀÒ h£Í¯½àÛ4Ù €ù³‘–·Ö/­y5¨DݘK›ítvf Œ;»Ùƒ´GîÛ0.áØéåß yL†íQÂS$ÂÁ·„î']GG ‘t?dü)#lâ wZøÔ^Vëú+QÌ…]ãx÷:™Zg<:ruhz/zeéHCÉÄ•rh˜!-Š\ÚîñÀ@@¯IŸ`TkL¼Ç5:ôï“RRG«²°%TkzF6¥yAÝzT'ã².Waí&ÀaÎmÿb$Œ&ZñÄÒ¯+Ó¼K˜ÚP§)äÓý+ê*Ç%À0Ô†ïuW!ѶGûã¸.0n—ЪLJǰ ÛKy)¸ÑÓâ‹ê~Œ';C¯£ÏÛMˆt”DlRÙ\¨…^«Cb¦Áo¶&j;89„‚»~UiçMpö*Cª×=W~9³q]‚gàô÷RŽ×^Iáµ´jzeÊq~Öðxí­Áܳóé-Y¥«aûZÌ‹&•=(#öÕªÕ¡Õ\ÌÑ‘«ÁÉA©¯æ\!]›i÷8²óä®?ŠÇ>l> æù½ Šzõœ¾¦”¬¤ø*îð¼5] ÃÙ0¼¤óHãÂS‚~º ”®D¼hbÙÏc"7{M)®'v Ó×ÓËà ÐõŽ0‹¡Z&ã™jK} Ú©u»óšçy·A,ËÁµj´Êï^pž—ŠŸÇ& ~Ø›WaÝáÛ)úŒ‹Ä Íœ6Ú¼d9¸®™gYn‹³ qÑÆ+uAß&vºMéJ@´ËTv5H9X$\ï9•’Šÿ®n'Xv¸JzªÜ^ÔE²„£[ªÔOãoü6HNBd”tKÁÌÈ=K‡\´;m«²¼0f{ë )%"í5!ÿï°_g¡1¸ú0í:LCÝÚ^Ò½§qaÍMºÿÀ.fûê„‹®D€(×Y›¦(š?öSÅ— -VyÉpv¯Â³ n…þ*<ó[ ‹7üªëoP;§{ ÷†…5¢“ÿÄ ™·R•Á+³tx&}p¯Œ2i7Ž'Sês KëÖa$ZdÇõ /º M+ò컄m~D¦DPŸûŠG¾âL$ ¹€ð6i-NW¶9ý*zNÆPCy}à>Õ*G.”¦—D…‡\•r—àz ˆÖñùÚ™à8âóFÈ8Á › ݤ“vuf˵/M.[nDì 7áÔa-ðÊ>CD×®2 Kè(Œê cqЖ _j\T;Ï4 ßÙ1wô"gÚmâcê`_1x˜g¨E˜ø ¯•‹Bù±$\ÐËÂJyäbf‡ð¸¬ÇÌ[°¬k…–·•Tù¬¨0T˜ý23bÙvÞöÀQ†svüñÍ«rG›TP¼Ÿ9Io–2žtž€q|!¾xÓÿèª4× „ê½sá9üÒ°­1ôÊÀ8€\Â~ˆ ½Ax¼D‡XÕ›<ÆëÖÎEl((·ïŽ\w `NáM,½Jz1]UxP\w0X¡ð’is^ ’®&/º)畦¦-âYÑz‰˜¢ò䘕7t¹Ì0ÔDi[1ŠR·;ªpòÀÁ¦_%ù;„Œ?Q·¥.M.û‘±¿£Zœ%¶ãa¸)1³è Ñ+{z[=,|=ʾ ‚¿…®±y&6,´/\Gß]U¢÷üƒFÐy~~¶ëç¯CÈei¯!ªÁƵßu雌ãâÚûृèÁøhªeH\ˆÕ(C†Ê¸ò¬Óîô‰Íé‘mqžÍ˜n샃mÒΔøÂºGD9¸¹ÆgìDÐÀØÊÏáÇÃÞ0“ࢢràÝÀ×ÔÜhÁˆ´B *µÞóÔx`Zsï†äŒAô˜8°Ü3BØð¼V—âQïÀXVÑ ¹ØƒgB‚†Cb¿‚ºZÍB -ÃfÌ/„'È·AÝùàs"¡5 ±Ê²‹Q$Ò´¤î©heÉh³ ¼ öäËè±Lû(ÛáÔÙBÕ€} /l„C±«_!æôFgfÁ QMBž3ê–AQ³Õ˜€y_# ã 3„TxÆ.TœJ0ô\x3jD¸)HHc†­Sí°yjkcê‡cf–¯Å£Ò_VßW·y÷¢-"1BŒ/í),ÇÐ`ð>XÍ7.Þ8ÞÕy¢òÄ<±ô]˜Mí¯›Ê¸¦áƒÄ÷b}ó>ÊûòÉ'%}ãm<Ò€åU–ް ³ ^{%Íï³N¼ióß‹ìÁ{”©Žã}g$r@g%Ÿ›@ð¢>eÿ„‘Œ4ŠÔ ±®l†Ã*19¨&ª¥°ŒLÃúb†¶ØNÚÅ-7–4G ~>ù3pH”@äeâ-0l¨ô€·36õ2«Ð:‘@¦ãŽpÓîß!?œÿ°lóõ•¿Øðêz°M¦X‚ï í6& ˜…W0±ïf'ÝX`Ù1¨JóÒm°lì‹egB´t~ù«]£aÝ‹¿ô¥c‘b:ÆÕW5ø[ªGÇöµZÊéÈŸÓå=ÄŸkvï“ÿ¥Þù1ÕóIìË\•µ°1^M°Ñàæ”m×e§Âc<ð«îlØ´qzÀIìƒÞ¸™å_‡º‹#ô@AgìŽo¨eXîËL7;ïÂHܶjNÍ#,ÇTIo iéRÍ™„¶Í¤Ëõ*½¯ ;¿ ÅnBl7”Œ¦v4¿Ú¢J ÜåŒêj£YüË¡Eétq¤¹@4‰ëª›ÉD9娾xï}qÈeºT!¬¯¤J:Ëawè½Ñ¨û@⢽©3ñû†ÇSX(bMK·€;10Ø`ôÌòëCë^§ã…9ÀNŽ ±#aÒN¤îã*-g®ž»~\tãÀð³s¶p_C¥¢JXeE§ž„¼|KØÍ^³»ãþª†Ôž( 7wyš°:ú4°CB%¦!`ˆãÀ!a*:Êqg]ý“kß ÀËÐ)Ž–‚âÉeO‹õÄ¿’fžq[R3ÕÍÁ`´Ý9ø Ú~šé¨í§Ÿ,Wêuˆ0zVùh¨©U´XpC?œ“£máÌh ®_}OÍýÌ‚E7 Uá~Z~Ìû¥/ž Úò2È—uR¦Tï"rò¼30€ÚqûÏ›ÐUoˆ_~½LÞ÷ØÍ[?b»Åó+†‚R—cãÁøýX(axá|”¨ µ&ÓËâõö[¢ª:Éò›|5ìÀ1øŽÌ³••Bx(„PË«’á¨GÕ×!)é|/ËŸ…49’+e%ïá±4AlV[°ÖŠ«ÃÿÕsjžCU`˜ëæûFóú>ÇÉ*Ë2G›6ì ¢\l8œ-`\$[”ŸK™÷)½L*ŸC€My–÷N‚ÑëÁŠ^Z}nôD3j[ +y‰ôÓª†Ö[vÍXù(ëd%ÊŸAF"²ôEµ/±žòÖ8GÆuΓ'äÐèäA#â 6­A92ÕW»RW’õùÇŒ*ÿŠowÜB…!e‚Ê© ^Q#|£‹^œS·V€ë*ð¨`TàúÔ‹‡Ü…ãk3MÛɤë".å†ó­P+ˆÙwŸ÷„÷Œ'½¿Ä›Óo/øþ–&PdÖíUQn,­Ú@U'zÍ‹ 2yQh ´"ܦt AÂ×”ÞˆS%홵úm–P;Ýb}Û‡c¯‹(xsoIG+pHNBZ"é2k0Úªv'ŸÚ]íØ.õ“{Ó¿¨ŸuÓú4"îyX\§$¡»ÎƒšZÁû`@E]ÿߥ=¥eý>?jjnJ+¨ DVP(ŒX|‹óœé¸Uw»îÅCŽŽ{`ÜT¾u›JB!ºÜƒaô‰+Nž¹kúò—DUyHTÕð™Ç€¨ëŠWZo|…e™‡¿¶’ž_ôÒ¾ÇÑâÍ ×@ë-^•HÿºaQíÕ¨Ô!;¢×VŸ0O·;úÆ!ãÀ=ŸuR0 VψdÃ~`:@ëŠ 8” íÁ@ ö#æ¨D““ƈk‚›±Óá$›ÝkçÜRsÁàÂ'ŒÝ;´Æ?_›IQåKaÏ*nPùöm^3NN8°[8fÍ9A×s¥ÿî®Öw^å=ÀÐk ^*‘ú«m¨ïòéãÀðŸâ3¾}{&ô¾ÖŸºf%¥>—ŒÛv«+6Ñ5€P\‘°b?Þˆ¡Ço+§uûªÙ/ kÞÏUUý"²–… ÌÓZ[\ɰ2jM:çÞûÍ óôxc¬pÙ&­á à~€²J8ÇÞ?†UÍV 2>Æm&ÿÚž¼!EÑ1áãšg-&ßlZ°e#°M""üMËñ,Áƒw…* ¡"€Æ¥^µ“Y˜4üËÃûì@ zôh¤AÏ ‰s¬ˆi9IgÙÊÙªt^5ˆZé:š_x_AÔ‘  [ºÐËé46\…ºdî-u+èya¾\Ä}<çq5Ž„—ù–Dß8€¡;Ä,\:#dF¡;?ͲÚÖþJü¸ü&mg0 º?Q+ðÌ Ó4ÀJìl^4ðà@æô·ÿeçL`Ô ƒðv“ü cSL °•J:»1ëƒAP;zm0ëçƒ+íˆ1jÊ…BAÈD*Ú ÌoÆÜ[6®š0èyii*ðEöì1wÌØ@º€ª ýH¨Aɶ…é‡àË‚ÓóFJ™îjŒõø"š¦ûØ»^: KÑ«<†1b½ODü3àñÌÂz‡ðåôóÆÎÒviþ:½YœªÕI37R9¨?Â-—+2œ]ŽFÛÖ¢)’¨úÍb㟖ûžP«H=×ZŸj…sø@n'¡!GâbíAæ)!Hôç{¿½¹åõƒs\¾ªä\IJÆÚŽâ‚M'¨žSm×87˿ ï4Ÿ@læà‰øƒx ûéR5Áˆ„~‡“b_ âÁ;H­ÕS·R‘Ü ÷U-Îlq°BíÉÁpérúSîÏn¡ÛÞ¡tÈw¨U‘õ^š³e»2Ä Í©= ÚᾇíUþôä"¸ˆãÒØ’‹Ñ¨2`ˆÇÞX¶Â—2ÝÂuxÖ²»)ñŸùI (}x rxÇÎÕ°”ã˜ƶȡ¥Dƒ‚^qJq×u[ðÒnˆON_n⺛SÑ+ñ‚ª!¿†S’{¥ƒ›:AÔ‡+8)ÖÕãÏmâP×ûvx¨Òíî­º»æÁuóõA2¿6¨À‹ãe¸ ŸÀH/&c¦Nc‹¡^Ð>¡¡šJi^Þúè£Û[ƒ:õÛ Né²øP!ù)´\¨OœàPpZë+f¨²7T÷fðÍÍ2ZÜà™٤·xgx‘ûpì4Ð1Ž¥ç“-å)?¬ã3T6ûp/ºòÈ>Aý{Ó8Ѥ{ Å‚AÙp‹Qô凾Qû_ÌFóó}úr7W¾O7ùÜs5çAT1ø¹ (­hõ2`¥)ä|„Ì’Üg#b0dÃå)Àùx©Ñu02Dö74nªß*G5 ³RpØw_ý!°ñ†ýù8ºz~M'þ2}£¢ ‰"–O6<ïRKœo×ö–9¼«œF¯Bg•Ù¡HÆ…ÂŒÀ¿`¹õl€0üâ…•?×yxRÛl©æ$Ð/¬÷.Ú € úò#ªwÞ¸f;î~*ª*î>¦:ÇL¦®‘/4cØAôkNìöJ 00%Nˆb08tƤœX<¹´üß‚µã,¬ði0 3Cìáì6ÙZÓIÏMý"È'¼JG Ãðp²Ý÷¡í wpý›œEš´PèÆ¸¼<Òü¬õL6ù9Ço¢Òµ4‰±Ë4{`X̬Nîâ¸ûcÏûÆî68ׇ <óxxH«ûÀÖ#^âi„ñànZ—|aÛwg*¼ÜW˜¥“7vñfNNÞÑôÄÖ ‚†k¬Ìãö~q@z!ÔÎA‚ {°þ š¢&¡bkNHâ.~»;@4N§a/ûúÜ¿E^r8Õ$™!ÌˤÇëìßnñ½:î§#ð¸K®ø;ò§Ü}Fïˆ Œqé4±DZŸ[ãWª¨} TxÞx+ÉD#³ß+Öè.@¥í%Ò+pèîûº\ufìú®ÝGf 6¬¶3„Ä¡~3¥>ÜþnZŸƒª†ýxøa餖LQX¼¤Ï mô§*±Á´´ª?$c4Óc£ù†Ú§fÎbñP -Íò%¾¶û4rø·O‚¸=àúb¼O)­è tñ.{«ûQÚK} 9/–…êxÊêÂŽ7Ñ¾šš¨’N9[1…ÚÒR ±ûÙ¶ÀàjÒ‰“O<¥?°Íÿžâiô˜cüçPã­‘ˆÑ{úh·Ggà4Ñn¯'0‰Ü¡/¯¿F`t8óG5ƒ½ª¤ŠïLýšvÆñÁ~ ½¤†…W³ãhîß‹·¾£UÕ'ƒÝq@@{ò¶œ_µy'¨ü¼Õ¤§ ;ÒÀ˜Òª$×”ýMSØTëÔïPûqžJÄŠ`elUÊò1å쀊Áñ\Ü(Ñ_T ׇpÝVÒ›b:†•»¿’6Æà ª¤Œ¯µí2§‚Õ¼ 0¸[x~ÃB¼gø íFNóGvž‰eÁÏy‘ó¦€è-|–YgÀ >>ᆯ¸Ë ñÁÇ»ª¥ Î¿ôô»ÿmyMí8±¸W¸„í¡t›„ÕÏ2TmH€÷]º éMAzñ~¡ic…þ¢ÓcñÄ_; ŽAs#/Ždª »¥ä ©¤Þ› á´Jz;Ôz,†èeãè¨à«,XæG£ýüçRj1ÏZ6iÝNµ†ZD³ðJƒHÅ!çHx|Ë¡óùóPÁ>tÁôŠk ?–ó‚¯ÿLóSxû«%CÏûtœÉìòï¥>GξuÃZôõbž¿Ÿó kÜÇçq§_Ì%[ꘆ”!>ïן(CíNµRû‰Óª°WÂ<Ãë¡Ûð ‰–:?tÎK`؉¤¯ ¿L”QWè›ÝÃxCyr,ÉÔx³êÜø2¼MÕ`p˜Gß#Ñ}ã5ñé{v`I¢D6.ŤyÌô#!ˆS!mÛæç@`>lnÖÆ¥td¿ðæxx/†§†ñ|œ.y°5<ç  Ç©Z:‚Å‘ÈP*„㾉û‹`/nzÏÆµ‚ûNû:Z€p…óo­[ç÷|,*v1óùç}éÁºïb2'H "ÅãÛ2¹; \âŽîœÁg}lç%¬Àw#E'`DyãF0?Ø Ô—û|»–x—åz,îúÀKÃ/ãÐOSøÅzcJ:÷âÔñÐÆÇƒ7À|/0cÒöi®3nŽ& <ÍΉsn®}>•ÿE€–, Ì2¼*ª*&ØS0¼ÔÄpØ ¨¼ŸÆá;¾º€cªšðk¿ºö-ùŒ„ç&ý½•)~ m~j.ÇOF‚:ßà¯1Áþ ‚ƒ|)§¯¥¬_¸ñÆÝþ;.þƒ^b¦£ H0/z8ÆÜëÖï!@·ßî«QlS4SBÀéTW\ðÅX>#AÍéæmðÀšSIòÄÈßýN¿x‰w,äù]iLŠÎ]Ê+ɪ=+DÏï€(À[ÃÚ€ÚÚ€¿‰°gáí/†Ò ëv™T ílÊd6ó(\P´<Œ :‡OÕH/ €`Uýeò¤ yÉÙïnÇÅfÔvHö/,jÅçÓ¶¯|«ç¿ùRb„ã拊}ì%ã^Š¿n' í/èp¼œ5¾ºá½Úaƒ,Öuö®¼uŸA^—~u@è´BÜÏ7š@œÕ;>r’ù2?Å]@·¡Jc¹Ì7TÚ&jú0öímÛ8ŸõªvAc?!¼<›οºÇü±#i¼ ŽMjàÝè¤Ò«øSƒn<…£©ÞÄÆM‡Ålüµ.'ôÊ rD¤‚ãΤnHf@»röÙ[V@2†%š¼¸"ÇâñÄ1cüGfñˆ…åët 0°.[ÖW¯ÎwM¯~o4=aX%ÿ~ŽöéQ1¦¥ø«D½ ±i[iÙø$‚ï 0–:Z«#3®#õÝí &NfœuÖæº±c7 I¹ùVùÐ幄q÷µ$ö6ðë>.âZ%ùÑüs2Ï“!u#BéÛéÃÀêyÿXª.ÅÓî2áÖˆ+šÕ­ÊÓNhX— 2ÆWw„*L»Å$JÅØMs”›Œ»Ú5ÆÑR­JòÃê•tJí€1C!láÖå,#öAš¦®ÚW¥¿Bûà )ì±ßÞsî˜Ïá´{ ¿iòËåHÛ;*¡Ç‘óAñì։ƞ—©mFÊûÀÞ™¼ê•%Ëb1ë’†üΕ!prèã¶¾3üáöºéëÒ=掻ƌ˜ó©ˆÌk;Sïž!fna˜F×ïn“ï¶’!‰O0¨ÂrÀ ñÖc[ÿžeóq ¡o»Gž4®àýp.w_»âWþ¡™o~º§}‚>„Ç2HÝŽ!»Ý€|:þ'€±*F<oÃ^ ñùO8¹gWëØñã·ñP²Ð¯R=çUÜkF­ë¹Š‡m™¹kÆŠ9ú9W1Ý(ý¿$—–”¢kJF5§Sÿ¼ø¬mÅ9j¢÷œ7v®YžÁÓx¥zÊ®k«Á³n¥ºþáëmZ}.³Æ(W½åk’©ØŽ/a¡]Ä ªÖ1ŒO:t £Îqq2‡úûAà¢ó9p¼T\û§¶òö/ÓïÛžh7pCãø{éÝ ½rÞŶ½/²ü Ð4ßY›á'Ïñv"ñvóG¢z[2˜ Ÿu+CŒë_âëÿ8UX~¿œIEND®B`‚kea-1.1.0/doc/guide/classify.xml0000664000175000017500000011377412772445242013423 00000000000000 ]> Client Classification
Client Classification Overview In certain cases it is useful to differentiate between different types of clients and treat them accordingly. Common reasons include: The clients represent different pieces of topology, e.g. a cable modem is different to the clients behind that modem. The clients have different behavior, e.g. a smart phone behaves differently to a laptop. The clients require different values for some options, e.g. a docsis3.0 cable modem requires different settings to docsis2.0 cable modem. It is envisaged that client classification will be used for changing the behavior of almost any part of the DHCP message processing, including the assignment of leases from different pools, the assignment of different options (or different values of the same options) etc. In the current release of the software however, there are only three mechanisms that take advantage of client classification: subnet selection, assignment of different options and, for DHCPv4 cable modems, the setting of specific options for use with the TFTP server address and the boot file field. The process of doing classification is conducted in three steps: Assess an incoming packet and assign it to zero or more classes. Choose a subnet, possibly based on the class information. Assign options, again possibly based on the class information. When determining which options to include in the response the server will examine the union of options from all of the assigned classes. In the case two or more classes include the same option, the value from the first class examined will be used. When choosing a subnet, the server will iterate over all of the subnets that are feasible given the information found in the packet (client address, relay address etc). It will use the first subnet it finds that either doesn't have a class associated with it or that has a class which matches one of the packet's classes. In the future the processing order of the various classes may be specified but for now it is being left unspecified and may change in future releases. As an example, imagine that an incoming packet matches two classes. Class "foo" defines values for an NTP server (option 42 in DHCPv4) and an SMTP server (option 69 in DHCPv4) while class "bar" defines values for an NTP server and a POP3 server (option 70 in DHCPv4). The server will examine the three options NTP, SMTP and POP3 and return any of them that the client requested. As the NTP server was defined twice the server will choose only one of the values for the reply: the class from which the value is obtained is unspecified. There are two methods of doing classification. The first is automatic and relies on examining the values in the vendor class options. Information from these options is extracted and a class name is constructed from it and added to the class list for the packet. The second allows you to specify an expression that is evaluated for each packet. If the result is true, the packet is a member of the class. Care should be taken with client classification as it is easy for clients that do not meet class criteria to be denied any service altogether.
Using Static Host Reservations In Classification Classes can be statically assigned to the clients using techniques described in and .
Using Vendor Class Information In Classification The server checks whether an incoming DHCPv4 packet includes the vendor class identifier option (60) or an incoming DHCPv6 packet includes the vendor class option (16). If it does, the content of that option is prepended with "VENDOR_CLASS_" and the result is interpreted as a class. For example, modern cable modems will send this option with value "docsis3.0" and so the packet will belong to class "VENDOR_CLASS_docsis3.0".
Using Expressions In Classification The expression portion of classification contains operators and values. All values are currently strings and operators take a string or strings and return another string. When all the operations have completed the result should be a value of "true" or "false". The packet belongs to the class (and the class name is added to the list of classes) if the result is "true". Expressions are written in standard format and can be nested. Expressions are pre-processed during the parsing of the configuration file and converted to an internal representation. This allows certain types of errors to be caught and logged during parsing. Examples of these errors include an incorrect number or types of arguments to an operator. The evaluation code will also check for this class of error and generally throw an exception, though this should not occur in a normally functioning system. Other issues, for example the starting position of a substring being outside of the substring or an option not existing in the packet, result in the operator returning an empty string. Expressions are a work in progress and the supported operators and values are limited. The expectation is that additional operators and values will be added over time, however the basic mechanisms will remain the same. List of Classification Values Name Example expression Example value Description String literal 'example' 'example' A string Hexadecimal string literal 0x5a7d 'Z}' A hexadecimal string IP address literal 10.0.0.1 0x0a000001 An IP address Integer literal 123 '123' A 32 bit unsigned integer value Binary content of the option option[123].hex '(content of the option)' The value of the option with given code from the packet as hex Option existence option[123].exists 'true' If the option with given code is present in the packet "true" else "false" DHCPv4 relay agent sub-option relay4[123].hex '(content of the RAI sub-option)' The value of sub-option with given code from the DHCPv4 Relay Agent Information option (option 82) DHCPv6 Relay Options relay6[nest].option[code].hex (value of the option) The value of the option with code "code" from the relay encapsulation "nest" DHCPv6 Relay Peer Address relay6[nest].peeraddr 2001:DB8::1 The value of the peer address field from the relay encapsulation "nest" DHCPv6 Relay Link Address relay6[nest].linkaddr 2001:DB8::1 The value of the link address field from the relay encapsulation "nest" Interface name of packet pkt.iface eth0 The name of the incoming interface of a DHCP packet. Source address of packet pkt.src 10.1.2.3 The IP source address of a DHCP packet. Destination address of packet pkt.dst 10.1.2.3 The IP destination address of a DHCP packet. Length of packet pkt.len 513 The length of a DHCP packet (UDP header field), expressed as a 32 bit unsigned integer. Hardware address in DHCPv4 packet pkt4.mac 0x010203040506 The value of the chaddr field of the DHCPv4 packet, hlen (0 to 16) bytes Hardware length in DHCPv4 packet pkt4.hlen 6 The value of the hlen field of the DHCPv4 packet padded to 4 bytes Hardware type in DHCPv4 packet pkt4.htype 6 The value of the htype field of the DHCPv4 packet padded to 4 bytes ciaddr field in DHCPv4 packet pkt4.ciaddr 192.0.2.1 The value of the ciaddr field of the DHCPv4 packet (IPv4 address, 4 bytes) giaddr field in DHCPv4 packet pkt4.giaddr 192.0.2.1 The value of the giaddr field of the DHCPv4 packet (IPv4 address, 4 bytes) yiaddr field in DHCPv4 packet pkt4.yiaddr 192.0.2.1 The value of the yiaddr field of the DHCPv4 packet (IPv4 address, 4 bytes) siaddr field in DHCPv4 packet pkt4.siaddr 192.0.2.1 The value of the siaddr field of the DHCPv4 packet (IPv4 address, 4 bytes) Message Type in DHCPv4 packet pkt4.msgtype 1 The value of the message type field in the DHCPv4 packet (expressed as a 32 bit unsigned integer). Transaction ID (xid) in DHCPv4 packet pkt4.transid 12345 The value of the transaction id in the DHCPv4 packet (expressed as a 32 bit unsigned integer). Message Type in DHCPv6 packet pkt6.msgtype 1 The value of the message type field in the DHCPv6 packet (expressed as a 32 bit unsigned integer). Transaction ID in DHCPv6 packet pkt6.transid 12345 The value of the transaction id in the DHCPv6 packet (expressed as a 32 bit unsigned integer). Vendor option existence (any vendor) vendor[*].exists true Returns whether a vendor option from any vendor is present ('true') or absent ('false'). Vendor option existence (specific vendor) vendor[4491].exists true Returns whether a vendor option from specified vendor (determined by its enterprise-id) is present ('true') or absent ('false'). Enterprise-id from vendor option vendor.enterprise 4491 If the vendor option is present, it returns the value of the enterprise-id field padded to 4 bytes. Returns "" otherwise. Vendor sub-option existence vendor[4491].option[1].exists true Returns 'true' if there is vendor option with specified enterprise-id and given sub-option is present. Returns 'false' otherwise. Vendor sub-option content vendor[4491].option[1].hex docsis3.0 Returns content of the specified sub-option of a vendor option with specified enterprise id. Returns '' if no such option or sub-option is present. Vendor class option existence (any vendor) vendor-class[*].exists true Returns whether a vendor class option from any vendor is present ('true') or absent ('false'). Vendor class option existence (specific vendor) vendor-class[4491].exists true Returns whether a vendor class option from specified vendor (determined by its enterprise-id) is present ('true') or absent ('false'). Enterprise-id from vendor class option vendor-class.enterprise 4491 If the vendor option is present, it returns the value of the enterprise-id field padded to 4 bytes. Returns "" otherwise. First data chunk from vendor class option vendor-class[4491].data docsis3.0 Returns content of the first data chunk from the vendor class option with specified enterprise-id. Returns "" if missing. Specific data chunk from vendor class option vendor-class[4491].data[3] docsis3.0 Returns content of the specified data chunk of a vendor class option with specified enterprise id. Returns '' if no such option or data chunk is present.
Notes:
Hexadecimal strings are converted into a string as expected. The starting "0X" or "0x" is removed and if the string is an odd number of characters a "0" is prepended to it. IP addresses are converted into strings of length 4 or 16. IPv4, IPv6, and IPv4 embedded IPv6 (e.g., IPv4 mapped IPv6) addresses are supported. Integers in an expression are converted to 32 bit unsigned integers and are represented as four-byte strings. For example 123 is represented as 0x0000007b. All expressions that return numeric values use 32-bit unsigned integers, even if the field in the packet is smaller. In general it is easier to use decimal notation to represent integers, but it is also possible to use hex notation. When using hex notation to represent an integer care should be taken to make sure the value is represented as 32 bits, e.g. use 0x00000001 instead of 0x1 or 0x01. Also, make sure the value is specified in network order, e.g. 1 is represented as 0x00000001. "option[code].hex" extracts the value of the option with the code "code" from the incoming packet. If the packet doesn't contain the option, it returns the empty string. The string is presented as a byte string of the option payload without the type code or length fields. "option[code].exists" checks if an option with the code "code" is present in the incoming packet. It can be used with empty options. "relay4[code].hex" attempts to extract the value of the sub-option "code" from the option inserted as the DHCPv4 Relay Agent Information (82) option. If the packet doesn't contain a RAI option, or the RAI option doesn't contain the requested sub-option, the expression returns an empty string. The string is presented as a byte string of the option payload without the type code or length fields. This expression is allowed in DHCPv4 only. "relay4" shares the same representation types as "option", for instance "relay4[code].exists" is supported. "relay6[nest]" allows access to the encapsulations used by any DHCPv6 relays that forwarded the packet. The "nest" level specifies the relay from which to extract the information, with a value of 0 indicating the relay closest to the DHCPv6 server. If the requested encapsulation doesn't exist an empty string "" is returned. This expression is allowed in DHCPv6 only. "relay6[nest].option[code]" shares the same representation types as "option", for instance "relay6[nest].option[code].exists" is supported. Expressions starting with "pkt4" can be used only in DHCPv4. They allows access to DHCPv4 message fields. "pkt6" refers to information from the client request. To access any information from an intermediate relay use "relay6". "pkt6.msgtype" and "pkt6.transid" output a 4 byte binary string for the message type or transaction id. For example the message type SOLICIT will be "0x00000001" or simply 1 as in "pkt6.msgtype == 1". Vendor option means Vendor-Identifying Vendor-specific Information option in DHCPv4 (code 125, see Section 4 of RFC 3925) and Vendor-specific Information Option in DHCPv6 (code 17, defined in Section 22.17 of RFC 3315). Vendor class option means Vendor-Identifying Vendor Class Option in DHCPv4 (code 124, see Section 3 of RFC 3925) in DHCPv4 and Class Option in DHCPv6 (code 16, see Section 22.16 of RFC 3315). Vendor options may have sub-options that are referenced by their codes. Vendor class options do not have sub-options, but rather data chunks, which are referenced by index value. Index 0 means the first data chunk, Index 1 is for the second data chunk (if present), etc. In the vendor and vendor-class constructs Asterisk (*) or 0 can be used to specify a wildcard enterprise-id value, i.e. it will match any enterprise-id value. Vendor Class Identifier (option 60 in DHCPv4) can be accessed using option[60] expression. RFC3925 and RFC3315 allow for multiple instances of vendor options to appear in a single message. The client classification code currently examines the first instance if more than one appear. For vendor.enterprise and vendor-class.enterprise expressions, the value from the first instance is returned. Please submit a feature request on Kea website if you need support for multiple instances. List of Classification Expressions Name Example Description Equal 'foo' == 'bar'Compare the two values and return "true" or "false"Not not ('foo' == 'bar')Logical negationAnd ('foo' == 'bar') and ('bar' == 'foo')Logical andOr ('foo' == 'bar') or ('bar' == 'foo')Logical orSubstringsubstring('foobar',0,3)Return the requested substringConcatconcat('foo','bar')Return the concatenation of the strings
Logical operators The Not, And and Or logical operators are the common operators. Not has the highest precedence and Or the lowest. And and Or are (left) associative, parentheses around a logical expression can be used to enforce a specific grouping, for instance in "A and (B or C)" (without parentheses "A and B or C" means "(A and B) or C").
Substring The substring operator "substring(value, start, length)" accepts both positive and negative values for the starting position and the length. For "start", a value of 0 is the first byte in the string while -1 is the last byte. If the starting point is outside of the original string an empty string is returned. "length" is the number of bytes to extract. A negative number means to count towards the beginning of the string but doesn't include the byte pointed to by "start". The special value "all" means to return all bytes from start to the end of the string. If length is longer than the remaining portion of the string then the entire remaining portion is returned. Some examples may be helpful: substring('foobar', 0, 6) == 'foobar' substring('foobar', 3, 3) == 'bar' substring('foobar', 3, all) == 'bar' substring('foobar', 1, 4) == 'ooba' substring('foobar', -5, 4) == 'ooba' substring('foobar', -1, -3) == 'oba' substring('foobar', 4, -2) == 'ob' substring('foobar', 10, 2) == ''
Concat The concat function "concat(string1, string2)" returns the concatenation of its two arguments. For instance: concat('foo', 'bar') == 'foobar'
The expression for each class is executed on each packet received. If the expressions are overly complex, the time taken to execute them may impact the performance of the server. If you need complex or time consuming expressions you should write a hook to perform the necessary work.
Configuring Classes A class contains three items: a name, a test expression and option data. The name must exist and must be unique amongst all classes. The test expression and option data are optional. The test expression is a string containing the logical expression used to determine membership in the class. The entire expression is in double quotes. The option data is a list which defines any options that should be assigned to members of this class. In the following example the class named "Client_foo" is defined. It is comprised of all clients whose client ids (option 61) start with the string "foo". Members of this class will be given 192.0.2.1 and 192.0.2.2 as their domain name servers. "Dhcp4": { "client-classes": [ { "name": "Client_foo", "test": "substring(option[61].hex,0,3) == 'foo'", "option-data": [ { "name": "domain-name-servers", "code": 6, "space": "dhcp4", "csv-format": true, "data": "192.0.2.1, 192.0.2.2" } ] }, ... ], ... } This example shows a client class being defined for use by the DHCPv6 server. In it the class named "Client_enterprise" is defined. It is comprised of all clients who's client identifiers start with the given hex string (which would indicate a DUID based on an enterprise id of 0xAABBCCDD). Members of this class will be given an 2001:db8:0::1 and 2001:db8:2::1 as their domain name servers. "Dhcp6": { "client-classes": [ { "name": "Client_enterprise", "test": "substring(option[1].hex,0,6) == 0x0002AABBCCDD'", "option-data": [ { "name": "dns-servers", "code": 23, "space": "dhcp6", "csv-format": true, "data": "2001:db8:0::1, 2001:db8:2::1" } ] }, ... ], ... }
Configuring Subnets With Class Information In certain cases it beneficial to restrict access to certain subnets only to clients that belong to a given class, using the "client-class" keyword when defining the subnet. Let's assume that the server is connected to a network segment that uses the 192.0.2.0/24 prefix. The Administrator of that network has decided that addresses from range 192.0.2.10 to 192.0.2.20 are going to be managed by the DHCP4 server. Only clients belonging to client class Client_foo are allowed to use this subnet. Such a configuration can be achieved in the following way: "Dhcp4": { "client-classes": [ { "name": "Client_foo", "test": "substring(option[61].hex,0,3) == 'foo'", "option-data": [ { "name": "domain-name-servers", "code": 6, "space": "dhcp4", "csv-format": true, "data": "192.0.2.1, 192.0.2.2" } ] }, ... ], "subnet4": [ { "subnet": "192.0.2.0/24", "pools": [ { "pool": "192.0.2.10 - 192.0.2.20" } ], "client-class": "Client_foo" }, ... ],, ... } The following example shows restricting access to a DHCPv6 subnet. This configuration will restrict use of the addresses 2001:db8:1::1 to 2001:db8:1::FFFF to members of the "Client_enterprise" class. "Dhcp6": { "client-classes": [ { "name": "Client_enterprise", "test": "substring(option[1].hex,0,6) == 0x0002AABBCCDD'", "option-data": [ { "name": "dns-servers", "code": 23, "space": "dhcp6", "csv-format": true, "data": "2001:db8:0::1, 2001:db8:2::1" } ] }, ... ], "subnet6": [ { "subnet": "2001:db8:1::/64", "pools": [ { "pool": "2001:db8:1::-2001:db8:1::ffff" } ], "client-class": "Client_enterprise" } ], ... }
Using Classes Currently classes can be used for two functions. They can supply options to the members of the class and they can be used to choose a subnet from which an address will be assigned to the class member. When supplying options, options defined as part of the class definition are considered "class globals". They will override any global options that may be defined and in turn will be overridden by any options defined for an individual subnet.
Classes and Hooks You may use a hook to classify your packets. This may be useful if the expression would either be complex or time consuming and be easier or better to write as code. Once the hook has added the proper class name to the packet the rest of the classification system will work as normal in choosing a subnet and selecting options. For a description of hooks see , for a description on configuring classes see and .
Debugging Expressions While you are constructing your classification expressions you may find it useful to enable logging see for a more complete description of the logging facility. To enable the debug statements in the classifciaton system you will need to set the severity to "DEBUG" and the debug level to at least 55. The specific loggers are "kea-dhcp4.eval" and "kea-dhcp6.eval". In order to understand the logging statements one must understand a bit about how expressions are evaluated, for a more complete description refer to the design document at . In brief there are two structures used during the evaluation of an expression: a list of tokens which represent the expressions and a value stack which represents the values being manipulated. The list of tokens is created when the configuration file is processed with most expressions and values being converted to a token. The list is organized in reverse Polish notation. During execution, the list will be traversed in order. As each token is executed it will be able to pop values from the top of the stack and eventually push its result on the top of the stack. Imagine the following expression: "test": "substring(option[61].hex,0,3) == 'foo'", This will result in the following tokens: option, number (0), number (3), substring, text ('foo'), equals In this example the first three tokens will simply push values onto the stack. The substring token will then remove those three values and compute a result that it places on the stack. The text option also places a value on the stack and finally the equals token removes the two tokens on the stack and places its result on the stack. When debug logging is enabled, each time a token is evaluated it will emit a log message indicating the values of any objects that were popped off of the value stack and any objects that were pushed onto the value stack. The values will be displayed as either text if the command is known to use text values or hexadecimal if the command either uses binary values or can manipulate either text or binary values. For expressions that pop multiple values off the stack, the values will be displayed in the order they were popped. For most expressions this won't matter but for the concat expression the values are displayed in reverse order from how they are written in the expression. Let us assume that the following test has been entered into the configuration. This example skips most of the configuration to concentrate on the test. "test": "substring(option[61].hex,0,3) == 'foo'", The logging might then resemble this: 2016-05-19 13:35:04.163 DEBUG [kea.eval/44478] EVAL_DEBUG_OPTION Pushing option 61 with value 0x666F6F626172 2016-05-19 13:35:04.164 DEBUG [kea.eval/44478] EVAL_DEBUG_STRING Pushing text string '0' 2016-05-19 13:35:04.165 DEBUG [kea.eval/44478] EVAL_DEBUG_STRING Pushing text string '3' 2016-05-19 13:35:04.166 DEBUG [kea.eval/44478] EVAL_DEBUG_SUBSTRING Popping length 3, start 0, string 0x666F6F626172 pushing result 0x666F6F 2016-05-19 13:35:04.167 DEBUG [kea.eval/44478] EVAL_DEBUG_STRING Pushing text string 'foo' 2016-05-19 13:35:04.168 DEBUG [kea.eval/44478] EVAL_DEBUG_EQUAL Popping 0x666F6F and 0x666F6F pushing result 'true' The debug logging may be quite verbose if you have a number of expressions to evaluate. It is intended as an aid in helping you create and debug your expressions. You should plan to disable debug logging when you have your expressions working correctly. You also may wish to include only one set of expressions at a time in the configuration file while debugging them in order to limit the log statements. For example when adding a new set of expressions you might find it more convenient to create a configuration file that only includes the new expressions until you have them working correctly and then add the new set to the main configuration file.
kea-1.1.0/doc/guide/kea-guide.html0000664000175000017500000246030412772742655013611 00000000000000Kea Administrator Reference Manual

Kea Administrator Reference Manual

This is the reference guide for Kea version 1.1.0.

Abstract

Kea is an open source implementation of the Dynamic Host Configuration Protocol (DHCP) servers, developed and maintained by Internet Systems Consortium (ISC).

This is the reference guide for Kea version 1.1.0. The most up-to-date version of this document (in PDF, HTML, and plain text formats), along with other documents for Kea, can be found at http://kea.isc.org/docs.


Table of Contents

1. Introduction
1.1. Supported Platforms
1.2. Required Software at Run-time
1.3. Kea Software
2. Quick Start
2.1. Quick Start Guide for DHCPv4 and DHCPv6 Services
2.2. Running the Kea Servers Directly
3. Installation
3.1. Packages
3.2. Installation Hierarchy
3.3. Building Requirements
3.4. Installation from Source
3.4.1. Download Tar File
3.4.2. Retrieve from Git
3.4.3. Configure Before the Build
3.4.4. Build
3.4.5. Install
3.5. Selecting the Configuration Backend
3.6. DHCP Database Installation and Configuration
3.6.1. Building with MySQL Support
3.6.2. Building with PostgreSQL support
3.6.3. Building with CQL (Cassandra) support
4. Kea Database Administration
4.1. Databases and Database Version Numbers
4.2. The kea-admin Tool
4.3. Supported Databases
4.3.1. memfile
4.3.2. MySQL
4.3.3. PostgreSQL
4.3.4. CQL (Cassandra)
4.3.5. Using Read-Only Databases with Host Reservations
4.3.6. Limitations Related to the use of SQL Databases
5. Kea Configuration
5.1. JSON Configuration Backend
5.1.1. JSON Syntax
5.1.2. Simplified Notation
6. Managing Kea with keactrl
6.1. Overview
6.2. Command Line Options
6.3. The keactrl Configuration File
6.4. Commands
6.5. Overriding the Server Selection
7. The DHCPv4 Server
7.1. Starting and Stopping the DHCPv4 Server
7.2. DHCPv4 Server Configuration
7.2.1. Introduction
7.2.2. Lease Storage
7.2.3. Hosts Storage
7.2.4. Interface Configuration
7.2.5. Issues with Unicast Responses to DHCPINFORM
7.2.6. IPv4 Subnet Identifier
7.2.7. Configuration of IPv4 Address Pools
7.2.8. Standard DHCPv4 Options
7.2.9. Custom DHCPv4 options
7.2.10. DHCPv4 Vendor Specific Options
7.2.11. Nested DHCPv4 Options (Custom Option Spaces)
7.2.12. Unspecified Parameters for DHCPv4 Option Configuration
7.2.13. Stateless Configuration of DHCPv4 Clients
7.2.14. Client Classification in DHCPv4
7.2.15. DDNS for DHCPv4
7.2.16. Next Server (siaddr)
7.2.17. Echoing Client-ID (RFC 6842)
7.2.18. Using Client Identifier and Hardware Address
7.2.19. DHCPv4-over-DHCPv6: DHCPv4 Side
7.3. Host Reservation in DHCPv4
7.3.1. Address Reservation Types
7.3.2. Conflicts in DHCPv4 Reservations
7.3.3. Reserving a Hostname
7.3.4. Including Specific DHCPv4 Options in Reservations
7.3.5. Reserving Next Server, Server Hostname and Boot File Name
7.3.6. Reserving Client Classes in DHCPv4
7.3.7. Storing Host Reservations in MySQL or PostgreSQL
7.3.8. Storing host reservations in CQL (Cassandra)
7.3.9. Fine Tuning DHCPv4 Host Reservation
7.4. Server Identifier in DHCPv4
7.5. How the DHCPv4 Server Selects a Subnet for the Client
7.5.1. Using a Specific Relay Agent for a Subnet
7.5.2. Segregating IPv4 Clients in a Cable Network
7.6. Duplicate Addresses (DHCPDECLINE Support)
7.7. Statistics in the DHCPv4 Server
7.8. Management API for the DHCPv4 Server
7.9. Supported DHCP Standards
7.10. DHCPv4 Server Limitations
8. The DHCPv6 Server
8.1. Starting and Stopping the DHCPv6 Server
8.2. DHCPv6 Server Configuration
8.2.1. Introduction
8.2.2. Lease Storage
8.2.3. Hosts Storage
8.2.4. Interface Selection
8.2.5. IPv6 Subnet Identifier
8.2.6. Unicast Traffic Support
8.2.7. Subnet and Address Pool
8.2.8. Subnet and Prefix Delegation Pools
8.2.9. Standard DHCPv6 Options
8.2.10. Custom DHCPv6 Options
8.2.11. DHCPv6 Vendor-Specific Options
8.2.12. Nested DHCPv6 Options (Custom Option Spaces)
8.2.13. Unspecified Parameters for DHCPv6 Option Configuration
8.2.14. IPv6 Subnet Selection
8.2.15. Rapid Commit
8.2.16. DHCPv6 Relays
8.2.17. Relay-Supplied Options
8.2.18. Client Classification in DHCPv6
8.2.19. DDNS for DHCPv6
8.2.20. DHCPv4-over-DHCPv6: DHCPv6 Side
8.3. Host Reservation in DHCPv6
8.3.1. Address/Prefix Reservation Types
8.3.2. Conflicts in DHCPv6 Reservations
8.3.3. Reserving a Hostname
8.3.4. Including Specific DHCPv6 Options in Reservations
8.3.5. Reserving Client Classes in DHCPv6
8.3.6. Storing Host Reservations in MySQL or PostgreSQL
8.3.7. Storing Host Reservations in CQL (Cassandra)
8.3.8. Fine Tuning DHCPv6 Host Reservation
8.4. Server Identifier in DHCPv6
8.5. Stateless DHCPv6 (Information-Request Message)
8.6. Support for RFC 7550
8.7. Using Specific Relay Agent for a Subnet
8.8. Segregating IPv6 Clients in a Cable Network
8.9. MAC/Hardware Addresses in DHCPv6
8.10. Duplicate Addresses (DECLINE Support)
8.11. Statistics in the DHCPv6 Server
8.12. Management API for the DHCPv6 Server
8.13. Supported DHCPv6 Standards
8.14. DHCPv6 Server Limitations
9. Lease Expiration in DHCPv4 and DHCPv6
9.1. Lease Reclamation
9.2. Configuring Lease Reclamation
9.3. Configuring Lease Affinity
9.4. Default Configuration Values for Leases Reclamation
9.5. Reclaiming Expired Leases with Command
10. The DHCP-DDNS Server
10.1. Starting and Stopping the DHCP-DDNS Server
10.2. Configuring the DHCP-DDNS Server
10.2.1. Global Server Parameters
10.2.2. TSIG Key List
10.2.3. Forward DDNS
10.2.4. Reverse DDNS
10.2.5. Example DHCP-DDNS Server Configuration
10.3. DHCP-DDNS Server Limitations
11. The LFC process
11.1. Overview
11.2. Command Line Options
12. Client Classification
12.1. Client Classification Overview
12.2. Using Static Host Reservations In Classification
12.3. Using Vendor Class Information In Classification
12.4. Using Expressions In Classification
12.4.1. Logical operators
12.4.2. Substring
12.4.3. Concat
12.5. Configuring Classes
12.6. Configuring Subnets With Class Information
12.7. Using Classes
12.8. Classes and Hooks
12.9. Debugging Expressions
13. Hooks Libraries
13.1. Introduction
13.2. Configuring Hooks Libraries
13.3. Available Hooks Libraries
13.3.1. user_chk: Checking User Access
13.3.2. Forensic Logging Hooks
14. Statistics
14.1. Statistics Overview
14.2. Statistics Lifecycle
14.3. Commands for Manipulating Statistics
14.3.1. statistic-get command
14.3.2. statistic-reset command
14.3.3. statistic-remove command
14.3.4. statistic-get-all command
14.3.5. statistic-reset-all command
14.3.6. statistic-remove-all command
15. Management API
15.1. Data Syntax
15.2. Using the Control Channel
15.3. Commands Supported by Both the DHCPv4 and DHCPv6 Servers
15.3.1. leases-reclaim
15.3.2. list-commands
15.3.3. shutdown
16. The libdhcp++ Library
16.1. Interface detection and Socket handling
17. Logging
17.1. Logging Configuration
17.1.1. Loggers
17.1.2. Logging Message Format
17.1.3. Logging During Kea Startup
18. Frequently Asked Questions
18.1. General Frequently Asked Questions
18.1.1. Where did the Kea name came from?
18.1.2. Feature X is not supported yet. When/if will it be available?
18.2. Frequently Asked Questions about DHCPv4
18.2.1. I set up a firewall, but the Kea server still receives the traffic. Why?
18.3. Frequently Asked Questions about DHCPv6
18.3.1. Kea DHCPv6 doesn't seem to get incoming traffic. I checked with tcpdump (or other traffic capture software) that the incoming traffic is reaching the box. What's wrong?
19. Acknowledgments

Chapter 1. Introduction

Kea is the next generation of DHCP software developed by ISC. It supports both DHCPv4 and DHCPv6 protocols along with their extensions, e.g. prefix delegation and dynamic updates to DNS.

Kea was initially developed as a part of the BIND 10 framework. In early 2014, ISC made the decision to discontinue active development of BIND 10 and continue development of Kea as standalone DHCP software.

This guide covers Kea version 1.1.0.

1.1. Supported Platforms

Kea is officially supported on Red Hat Enterprise Linux, CentOS, Fedora and FreeBSD systems. It is also likely to work on many other platforms: Kea 1.1.0 builds have been tested on (in no particular order) Red Hat Enteprise Linux 6.4, Debian GNU/Linux 7, Ubuntu 12.04, Ubuntu 14.04, Ubuntu 16.04, Fedora Linux 19, Fedora 20, Fedora 22, CentOS Linux 7, NetBSD 6, FreeBSD 10.3, OpenBSD 5.7, OpenBSD 6.0, OS X 10.10, OS X 10.11.

There are currently no plans to port Kea to Windows platforms.

1.2. Required Software at Run-time

Running Kea uses various extra software which may not be provided in the default installation of some operating systems, nor in the standard package collections. You may need to install this required software separately. (For the build requirements, also see Section 3.3, “Building Requirementsâ€.)

  • Kea supports two cryptographic libraries: Botan and OpenSSL. Only one of them is required to be installed during compilation. If using Botan, Kea requires the Botan cryptographic library for C++ (http://botan.randombit.net/), version 1.8, 1.9 or 1.10. If OpenSSL is used, (http://www.openssl.org/), then Kea requires the OpenSSL C++ library version 1.0.*. Support for later versions of Botan and OpenSSL will be added in future releases of Kea.
  • Kea uses the log4cplus C++ logging library (http://log4cplus.sourceforge.net/). It requires log4cplus version 1.0.3 or later.
  • In order to store lease information in a MySQL database, Kea requires MySQL headers and libraries. This is an optional dependency in that Kea can be built without MySQL support.
  • In order to store lease information in a PostgreSQL database, Kea requires PostgreSQL headers and libraries. This is an optional dependency in that Kea can be built without PostgreSQL support.
  • In order to store lease information in a Cassandra database (CQL), Kea requires Cassandra headers and libraries. This is an optional dependency in that Kea can be built without Cassandra support.

1.3. Kea Software

Kea is modular. Part of this modularity is accomplished using multiple cooperating processes which, together, provide the server functionality. The following software is included with Kea:

  • keactrl — Tool to start, stop, reconfigure, and report status for the Kea servers.
  • kea-dhcp4 — The DHCPv4 server process. This process responds to DHCPv4 queries from clients.
  • kea-dhcp6 — The DHCPv6 server process. This process responds to DHCPv6 queries from clients.
  • kea-dhcp-ddns — The DHCP Dynamic DNS process. This process acts as an intermediary between the DHCP servers and DNS servers. It receives name update requests from the DHCP servers and sends DNS Update messages to the DNS servers.
  • kea-admin — A useful tool for database backend maintenance (creating a new database, checking versions, upgrading etc.)
  • kea-lfc — This process removes redundant information from the files used to provide persistent storage for the memfile data base backend. While it can be run standalone, it is normally run as and when required by the Kea DHCP servers.
  • perfdhcp — A DHCP benchmarking tool which simulates multiple clients to test both DHCPv4 and DHCPv6 server performance.

The tools and modules are covered in full detail in this guide. In addition, manual pages are also provided in the default installation.

Kea also provides C++ libraries and programmer interfaces for DHCP. These include detailed developer documentation and code examples.

Chapter 2. Quick Start

This section describes the basic steps needed to get Kea up and running. For further details, full customizations, and troubleshooting, see the respective chapters in the Kea guide.

2.1. Quick Start Guide for DHCPv4 and DHCPv6 Services

  1. Install required run-time and build dependencies. See Section 3.3, “Building Requirements†for details.
  2. Download Kea source tarball from ISC.org downloads page or ISC ftp server.

  3. Extract the tarball. For example:

    $ tar xvzf kea-1.1.0.tar.gz

  4. Go into the source directory and run the configure script:

    $ cd kea-1.1.0
    $ ./configure [your extra parameters]

  5. Build it:

    $ make

  6. Install it (by default it will be placed in /usr/local/, so it is likely that you will need root privileges for this step):

    # make install

  7. Edit the configuration file which by default is installed in [kea-install-dir]/etc/kea/kea.conf and contains configuration for all Kea services. Configuration choices for DHCPv4 and DHCPv6 services are described in Section 7.2, “DHCPv4 Server Configuration†and Section 8.2, “DHCPv6 Server Configurationâ€:w respectively.

  8. In order to start the DHCPv4 server in background, run the following command (as root):

    # keactrl start -s dhcp4

    Or run the following command to start DHCPv6 server instead:

    # keactrl start -s dhcp6

    Note that it is also possible to start both servers simultaneously:

    $ keactrl start

  9. Verify that Kea server(s) are running:

    # keactrl status

    A server status of "inactive" may indicate a configuration error. Please check the log file (by default named [kea-install-dir]/var/kea/kea-dhcp4.log or [kea-install-dir]/var/kea/kea-dhcp6.log) for the details of the error.

  10. If the server has been started successfully, test that it is responding to DHCP queries and that the client receives a configuration from the server; for example, use the ISC DHCP client.

  11. Stop running the server(s):

    # keactrl stop

For instructions specific to your system, please read the system specific notes, available on the Kea web site.

The details of keactrl script usage can be found in Chapter 6, Managing Kea with keactrl.

2.2. Running the Kea Servers Directly

The Kea servers can be started directly, without the need to use the keactrl. To start the DHCPv4 server run the following command:

# kea-dhcp4 -c /path/to/your/kea4/config/file.json

Similarly, to start the DHCPv6 server run the following command:

# kea-dhcp6 -c /path/to/your/kea6/config/file.json

Chapter 3. Installation

3.1. Packages

Some operating systems or software package vendors may provide ready-to-use, pre-built software packages for Kea. Installing a pre-built package means you do not need to install the software required only to build Kea and do not need to make the software.

FreeBSD ports, NetBSD pkgsrc, and Debian testing package collections provide all the prerequisite packages.

3.2. Installation Hierarchy

The following is the directory layout of the complete Kea installation. (All directory paths are relative to the installation directory):

  • bin/ — utility programs.
  • etc/kea/ — configuration files.
  • include/ — C++ development header files.
  • lib/ — libraries.
  • sbin/ — server software and commands used by the system administrator.
  • share/kea/ — configuration specifications and examples.
  • share/doc/kea/ — this guide, other supplementary documentation, and examples.
  • share/man/ — manual pages (online documentation).
  • var/kea/ — server identification, lease databases, and log files.

3.3. Building Requirements

In addition to the run-time requirements (listed in Section 1.2, “Required Software at Run-timeâ€), building Kea from source code requires various development include headers and program development tools.

Note

Some operating systems have split their distribution packages into a run-time and a development package. You will need to install the development package versions, which include header files and libraries, to build Kea from the source code.

Building from source code requires the following software installed on the system:

  • Boost build-time headers (http://www.boost.org/). At least Boost version 1.41 is required. When header-only Boost error code is not available or wanted, the Boost system library is required too.

  • Botan (version 1.8, 1.9 or 1.10) or OpenSSL (versions 1.0.*).

  • log4cplus (at least version 1.0.3) development include headers.

  • A C++ compiler and standard development headers. Kea 1.1.0 builds have been tested with GCC g++ 4.2.1, 4.4.7, 4.6.3, 4.8.3, 4.8.4, 4.8.5, 5.4.0; Clang++ 3.4.1; and Apple Clang++ 703.0.31.

  • The development tools automake, libtool, pkg-config.

  • The MySQL client and the client development libraries, when using the --with-dhcp-mysql configuration flag to build the Kea MySQL database backend. In this case an instance of the MySQL server running locally or on a machine reachable over a network is required. Note that running the unit tests requires a local MySQL server.

  • The PostgreSQL client and the client development libraries, when using the --with-dhcp-pgsql configuration flag to build the Kea PostgreSQL database backend. In this case an instance of the PostgreSQL server running locally or on some other machine, reachable over the network from the machine running Kea, is required. Note that running the unit tests requires a local PostgreSQL server.

  • googletest (version 1.6 or later), when using the --with-gtest configuration option to build the unit tests.

  • The documentation generation tools elinks, docbook-xsl, libxslt and Doxygen, if using the --enable-generate-docs configuration option to create the documentation.

Visit the user-contributed wiki at http://kea.isc.org/wiki/SystemSpecificNotes for system-specific installation tips.

3.4. Installation from Source

Kea is open source software written in C++. It is freely available in source code form from ISC as a downloadable tar file. A copy of the Kea source code repository is accessible from Github (https://github.com/isc-projects/kea). Kea may also be available in pre-compiled ready-to-use packages from operating system vendors.

3.4.1. Download Tar File

The Kea release tarballs may be downloaded from: http://ftp.isc.org/isc/kea/ (using FTP or HTTP).

3.4.2. Retrieve from Git

Downloading this "bleeding edge" code is recommended only for developers or advanced users. Using development code in a production environment is not recommended.

Note

When building from source code retrieved via Git, additional software will be required: automake (v1.11 or later), libtoolize, and autoconf (v2.59 or later). These may need to be installed.

The latest development code is available on Github (see https://github.com/isc-projects/kea). The Kea source is public and development is done in the “master†branch.

The code can be checked out from https://github.com/isc-projects/kea.git:

$ git clone https://github.com/isc-projects/kea.git

The code checked out from the git repository does not include the generated configure script, Makefile.in files, nor their related build files. They can be created by running autoreconf with the --install switch. This will run autoconf, aclocal, libtoolize, autoheader, automake, and related commands.

Write access to the Kea repository is only granted to ISC staff. If you are a developer planning to contribute to Kea, please fork our Github repository and use the "pull request" mechanism to request integration of your code. Please consult https://help.github.com/articles/fork-a-repo/ for help on how to fork a Github repository. The Kea Developer's Guide contains more information about the process, as well as describing the requirements for contributed code to be accepted by ISC.

3.4.3. Configure Before the Build

Kea uses the GNU Build System to discover build environment details. To generate the makefiles using the defaults, simply run:

$ ./configure

Run ./configure with the --help switch to view the different options. Some commonly-used options are:

--prefix
Define the installation location (the default is /usr/local).
--with-boost-include
Define the path to find the Boost headers.
--with-botan-config
Specify the path to the botan-config script to build with Botan for cryptographic functions.
--with-dhcp-mysql
Build Kea with code to allow it to store leases (and access host reservations) in a MySQL database.
--with-dhcp-pgsql
Build Kea with code to allow it to store leases (and access host reservations) in a PostgreSQL database.
--with-gtest-source
Enable the building of the C++ Unit Tests using the Google Test framework. This option specifies the path to the gtest source. (If the framework is not installed on your system, it can be downloaded from https://code.google.com/p/googletest.)
--with-log4cplus
Define the path to find the Log4cplus headers and libraries.
--with-openssl
Replace Botan by the OpenSSL the cryptographic library. By default configure searches for a valid Botan installation: if one is not found, it searches for OpenSSL.

Note

For instructions concerning the installation and configuration of database backends for Kea, see Section 3.6, “DHCP Database Installation and Configurationâ€. For information concerning the configuration backends, see Section 3.5, “Selecting the Configuration Backendâ€.

For example, the following command configures Kea to find the Boost headers in /usr/pkg/include, specifies that PostgreSQL support should be enabled, and sets the installation location to /opt/kea:

$ ./configure \
      --with-boost-include=/usr/pkg/include \
      --with-dhcp-pgsql=/usr/local/bin/pg_config \
      --prefix=/opt/kea

If you have some problems with building Kea using the header-only Boost code or you'd like to use the Boost system library (assumed for the sake of this example to be located in /usr/pkg/lib):

$ ./configure \
      --with-boost-libs=-lboost_system \
      --with-boost-lib-dir=/usr/pkg/lib

If configure fails, it may be due to missing or old dependencies.

If configure succeeds, it displays a report with the parameters used to build the code. This report is saved into the file config.report and is also embedded into the executable binaries, e.g., kea-dhcp4.

3.4.4. Build

After the configure step is complete, build the executables from the C++ code and prepare the Python scripts by running the command:

$ make

3.4.5. Install

To install the Kea executables, support files, and documentation, issue the command:

$ make install

Do not use any form of parallel or job server options (such as GNU make's -j option) when performing this step: doing so may cause errors.

Note

The install step may require superuser privileges.

If required, run ldconfig as root with /usr/local/lib (or with prefix/lib if configured with --prefix) in /etc/ld.so.conf (or the relevant linker cache configuration file for your OS):

$ ldconfig

Note

If you do not run ldconfig where it is required, you may see errors like the following:

	      program: error while loading shared libraries: libkea-something.so.1:
	      cannot open shared object file: No such file or directory
	    

3.5. Selecting the Configuration Backend

Kea 0.9 introduced configuration backends that are switchable during the compilation phase. Only one backend, JSON, is currently supported.

JSON
JSON is the new default configuration backend that allows Kea to read JSON configuration files from disk. It does not require any framework and thus is considered more lightweight. It will allow dynamic on-line reconfiguration, but lacks remote capabilities (i.e. no RESTful API).

3.6. DHCP Database Installation and Configuration

Kea stores its leases in a lease database. The software has been written in a way that makes it possible to choose which database product should be used to store the lease information. At present, Kea supports four database backends: MySQL, PostgreSQL, Cassandra and Memfile. To limit external dependencies, MySQL, PostgreSQL and Cassandra support are disabled by default and only Memfile is available. Support for the optional external database backend must be explicitly included when Kea is built. This section covers the building of Kea with one of the optional backends and the creation of the lease database.

Note

When unit tests are built with Kea (the --with-gtest configuration option is specified), the databases must be manually pre-configured for the unit tests to run. The details of this configuration can be found in the Kea Developer's Guide.

3.6.1. Building with MySQL Support

Install MySQL according to the instructions for your system. The client development libraries must be installed.

Build and install Kea as described in Chapter 3, Installation, with the following modification. To enable the MySQL database code, at the "configure" step (see Section 3.4.3, “Configure Before the Buildâ€), the --with-dhcp-mysql switch should be specified:

./configure [other-options] --with-dhcp-mysql

If MySQL was not installed in the default location, the location of the MySQL configuration program "mysql_config" should be included with the switch, i.e.

./configure [other-options] --with-dhcp-mysql=path-to-mysql_config

See Section 4.3.2.1, “First Time Creation of the MySQL Database†for details regarding MySQL database configuration.

3.6.2. Building with PostgreSQL support

Install PostgreSQL according to the instructions for your system. The client development libraries must be installed. Client development libraries are often packaged as "libpq".

Build and install Kea as described in Chapter 3, Installation, with the following modification. To enable the PostgreSQL database code, at the "configure" step (see Section 3.4.3, “Configure Before the Buildâ€), the --with-dhcp-pgsql switch should be specified:

./configure [other-options] --with-dhcp-pgsql

If PostgreSQL was not installed in the default location, the location of the PostgreSQL configuration program "pg_config" should be included with the switch, i.e.

./configure [other-options] --with-dhcp-pgsql=path-to-pg_config

See Section 4.3.3.1, “First Time Creation of the PostgreSQL Database†for details regarding PostgreSQL database configuration.

3.6.3. Building with CQL (Cassandra) support

Install Cassandra according to the instructions for your system. The Cassandra project website contains useful pointers: http://cassandra.apache.org.

Download and compile cpp-driver from DataStax. For details regarding dependencies for building cpp-driver, see the project homepage https://github.com/datastax/cpp-driver. In June 2016, the following commands were used:

$ git clone https://github.com/datastax/cpp-driver
$ cd cpp-driver
$ mkdir build
$ cmake ..
$ make

As of June 2016, cpp-driver does not include cql_config script yet. Work is in progress to contribute such a script to the cpp-driver project but, until that is complete, intermediate steps that need to be conducted. A cql_config script is present in the tools/ directory of the Kea sources. Before using it, please edit cql_config_defines.sh in the same directory and change the environment variable CPP_DRIVER_PATH to point to the directory, where cpp-driver sources are located. (If the cpp-driver sources already provide cql_config script please use that rather than the version from Kea sources.)

Build and install Kea as described in Chapter 3, Installation, with the following modification. To enable the Cassandra (CQL) database code, at the "configure" step (see Section 3.4.3, “Configure Before the Buildâ€), do:

./configure [other-options] --with-cql=path-to-cql_config

Chapter 4. Kea Database Administration

4.1. Databases and Database Version Numbers

Kea supports storing leases and host reservations (i.e. static assignments of addresses, prefixes and options) in one of the several supported databases. As future versions of Kea are released, the structure of those databases will change. For example, Kea currently only stores lease information and host reservations. Future versions of Kea will store additional data such as subnet definitions: the database structure will need to be updated to accomdate the extra information.

A given version of Kea expects a particular structure in the database and checks for this by examining the version of database it is using. Separate version numbers are maintained for backend databases, independent of the version of Kea itself. It is possible that the backend database version will stay the same through several Kea revisions: similarly, it is possible that the version of backend database may go up several revisions during a Kea upgrade. Versions for each database are independent, so an increment in the MySQL database version does not imply an increment in that of PostgreSQL.

Backend versions are specified in a major.minor format. The minor number is increased when there are backward compatible changes introduced. For example, the addition of a new index. It is desirable, but not mandatory to apply such a change; you can run on older database version if you want to. (Although, in the example given, running without the new index may be at the expense of a performance penalty.) On the other hand, the major number is increased when an incompatible change is introduced, for example an extra column is added to a table. If you try to run Kea software on a database that is too old (as signified by mismatched backend major version number), Kea will refuse to run: administrative action will be required to upgrade the database.

4.2. The kea-admin Tool

To manage the databases, Kea provides the kea-admin tool. It is able to initialize a new database, check its version number, perform a database upgrade, and dump lease data to a text file.

kea-admin takes two mandatory parameters: command and backend. Additional, non-mandatory options may be specified. Currently supported commands are:

  • lease-init — Initializes a new lease database. This is useful during a new Kea installation. The database is initialized to the latest version supported by the version of the software being installed.
  • lease-version — Reports the lease database version number. This is not necessarily equal to the Kea version number as each backend has its own versioning scheme.
  • lease-upgrade — Conducts a lease database upgrade. This is useful when upgrading Kea.
  • lease-dump — Dumps the contents of the lease database (for MySQL, PostgreSQL or CQL backends) to a CSV (comma separated values) text file. The first line of the file contains the column names. This is meant to be used as a diagnostic tool, so it provides a portable, human-readable form of the lease data.

backend specifies the backend type. Currently supported types are:

  • memfile — Lease information is stored on disk in a text file.
  • mysql — Lease information is stored in a MySQL relational database.
  • pgsql — Lease information is stored in a PostgreSQL relational database.
  • cql — Lease information is stored in a CQL database.

Additional parameters may be needed, depending on your setup and specific operation: username, password and database name or the directory where specific files are located. See the appropriate manual page for details (man 8 kea-admin).

4.3. Supported Databases

The following table presents the capabilities of available backends. Please refer to the specific sections dedicated to each backend to better understand their capabilities and limitations. Choosing the right backend may be essential for success or failure of your deployment.

Table 4.1. List of available backends

FeatureMemfileMySQLPostgreSQLCQL(Cassandra)
StatusStableStableStableExperimental
Data formatCSV fileSQL RMDBSQL RMDBNoSQL database (CQL)
Leasesyesyesyesyes
Host Reservationsnoyesyesno
Options defined on per host basisnoyesyesno


4.3.1. memfile

The memfile backend is able to store lease information, but is not able to store host reservation details: these must be stored in the configuration file. (There are no plans to add a host reservations storage capability to this backend.)

No special initialization steps are necessary for the memfile backend. During the first run, both kea-dhcp4 and kea-dhcp6 will create an empty lease file if one is not present. Necessary disk write permission is required.

4.3.1.1. Upgrading Memfile Lease Files from an Earlier Version of Kea

There are no special steps required to upgrade memfile lease files from an earlier version of Kea to a new version of Kea. During startup the servers will check the schema version of the lease files against their own. If there is a mismatch, the servers will automatically launch the LFC process to convert the files to the server's schema version. While this mechanism is primarily meant to ease the process of upgrading to newer versions of Kea, it can also be used for downgrading should the need arise. When upgrading, any values not present in the original lease files will be assigned appropriate default values. When downgrading, any data present in the files but not in the server's schema will be dropped. If you wish to convert the files manually, prior to starting the servers you may do so by running the LFC process yourself. See Chapter 11, The LFC process for more information.

4.3.2. MySQL

MySQL is able to store leases, host reservations and options defined on a per host basis. This section can be safely ignored if you chose to store the data in other backends.

4.3.2.1. First Time Creation of the MySQL Database

If you are setting the MySQL database for the first time, you need to create the database area within MySQL and set up the MySQL user ID under which Kea will access the database. This needs to be done manually: kea-admin is not able to do this for you.

To create the database:

  1. Log into MySQL as "root":

    $ mysql -u root -p
    Enter password:
    mysql>
    

  2. Create the MySQL database:

    mysql> CREATE DATABASE database-name;
    

    (database-name is the name you have chosen for the database.)

  3. Create the user under which Kea will access the database (and give it a password), then grant it access to the database tables:

    mysql> CREATE USER 'user-name'@'localhost' IDENTIFIED BY 'password';
    mysql> GRANT ALL ON database-name.* TO 'user-name'@'localhost';
    

    (user-name and password are the user ID and password you are using to allow Keas access to the MySQL instance. All apostrophes in the command lines above are required.)

  4. At this point, you may elect to create the database tables. (Alternatively, you can exit MySQL and create the tables using the kea-admin tool, as explained below.) To do this:

    mysql> CONNECT database-name;
    mysql> SOURCE path-to-kea/share/kea/scripts/mysql/dhcpdb_create.mysql
    

    (path-to-kea is the location where you installed Kea.)

  5. Exit MySQL:

    mysql> quit
    Bye
    $
    

If you elected not to create the tables in step 4, you can do so now by running the kea-admin tool:

$ kea-admin lease-init mysql -u database-user -p database-password -n database-name

(Do not do this if you did create the tables in step 4.) kea-admin implements rudimentary checks: it will refuse to initialize a database that contains any existing tables. If you want to start from scratch, you must remove all data manually. (This process is a manual operation on purpose to avoid possibly irretrievable mistakes by kea-admin.)

4.3.2.2. Upgrading a MySQL Database from an Earlier Version of Kea

Sometimes a new Kea version may use newer database schema, so there will be a need to upgrade the existing database. This can be done using the kea-admin lease-upgrade command.

To check the current version of the database, use the following command:

$ kea-admin lease-version mysql -u database-user -p database-password -n database-name

(See Section 4.1, “Databases and Database Version Numbers†for a discussion about versioning.) If the version does not match the minimum required for the new version of Kea (as described in the release notes), the database needs to be upgraded.

Before upgrading, please make sure that the database is backed up. The upgrade process does not discard any data but, depending on the nature of the changes, it may be impossible to subsequently downgrade to an earlier version. To perform an upgrade, issue the following command:

$ kea-admin lease-upgrade mysql -u database-user -p database-password -n database-name

4.3.3. PostgreSQL

A PostgreSQL database must be set up if you want Kea to store lease and other information in PostgreSQL. This step can be safely ignored if you are using other database backends.

4.3.3.1. First Time Creation of the PostgreSQL Database

The first task is to create both the lease database and the user under which the servers will access it. A number of steps are required:

  1. Log into PostgreSQL as "root":

    $ sudo -u postgres psql postgres
    Enter password:
    postgres=#
    

  2. Create the database:

    postgres=# CREATE DATABASE database-name;
    CREATE DATABASE
    postgres=#
    

    (database-name is the name you have chosen for the database.)

  3. Create the user under which Kea will access the database (and give it a password), then grant it access to the database:

    postgres=# CREATE USER user-name WITH PASSWORD 'password';
    CREATE ROLE
    postgres=# GRANT ALL PRIVILEGES ON DATABASE database-name TO user-name;
    GRANT
    postgres=#
    

  4. Exit PostgreSQL:

    postgres=# \q
    Bye
    $
    

  5. At this point you are ready to create the database tables. This can be done using the kea-admin tool as explained in the next section (recommended), or manually. To create the tables manually enter the following command. Note that PostgreSQL will prompt you to enter the new user's password you specified in Step 3. When the command completes you will be returned to the shell prompt. You should see output similar to following:

    $ psql -d database-name -U user-name -f path-to-kea/share/kea/scripts/pgsql/dhcpdb_create.pgsql
    Password for user user-name:
    CREATE TABLE
    CREATE INDEX
    CREATE INDEX
    CREATE TABLE
    CREATE INDEX
    CREATE TABLE
    START TRANSACTION
    INSERT 0 1
    INSERT 0 1
    INSERT 0 1
    COMMIT
    CREATE TABLE
    START TRANSACTION
    INSERT 0 1
    COMMIT
    $
    

    (path-to-kea is the location where you installed Kea.)

    If instead you encounter an error like:

    psql: FATAL:  no pg_hba.conf entry for host "[local]", user "user-name", database "database-name", SSL off
    

    ... you will need to alter the PostgreSQL configuration. Kea uses password authentication when connecting to the database and must have the appropriate entries added to PostgreSQL's pg_hba.conf file. This file is normally located in the primary data directory for your PostgreSQL server. The precise path may vary but the default location for PostgreSQL 9.3 on Centos 6.5 is: /var/lib/pgsql/9.3/data/pg_hba.conf.

    Assuming Kea is running on the same host as PostgreSQL, adding lines similar to following should be sufficient to provide password-authenticated access to Kea's database:

    local   database-name    user-name                                 password
    host    database-name    user-name          127.0.0.1/32           password
    host    database-name    user-name          ::1/128                password
    

    These edits are primarily intended as a starting point not a definitive reference on PostgreSQL administration or database security. Please consult your PostgreSQL user manual before making these changes as they may expose other databases that you run. It may be necessary to restart PostgreSQL in order for these changes to take effect.

4.3.3.2. Initialize the PostgreSQL Database Using kea-admin

If you elected not to create the tables manually, you can do so now by running the kea-admin tool:

$ kea-admin lease-init pgsql -u database-user -p database-password -n database-name

Do not do this if you already created the tables in manually. kea-admin implements rudimentary checks: it will refuse to initialize a database that contains any existing tables. If you want to start from scratch, you must remove all data manually. (This process is a manual operation on purpose to avoid possibly irretrievable mistakes by kea-admin.)

4.3.3.3. Upgrading a PostgreSQL Database from an Earlier Version of Kea

The PostgreSQL database schema can be upgraded using the same tool and commands as described in Section 4.3.2.2, “Upgrading a MySQL Database from an Earlier Version of Keaâ€, with the exception that the "pgsql" database backend type must be used in the commands.

Use the following command to check the current schema version:

$ kea-admin lease-version pgsql -u database-user -p database-password -n database-name

Use the following command to perform an upgrade:

$ kea-admin lease-upgrade pgsql -u database-user -p database-password -n database-name

4.3.4. CQL (Cassandra)

Cassandra, or Cassandra Query Language (CQL), is the newest backend added to Kea. Since it was added recently and has not undergone as much testing as other backends, it is considered experimental: please use with caution. The CQL backend is currently able to store leases only. The ability to store host reservations will likely be added some time in the future.

The CQL database must be properly set up if you want Kea to store information in CQL. This section can be safely ignored if you chose to store the data in other backends.

4.3.4.1. First Time Creation of the Cassandra Database

If you are setting up the CQL database for the first time, you need to create the keyspace area within CQL. This needs to be done manually: kea-admin is not able to do this for you.

To create the database:

  1. Export CQLSH_HOST environemnt variable:

    $ export CQLSH_HOST=localhost
    

  2. Log into CQL:

    $ cqlsh
    cql>
    

  3. Create the CQL keyspace:

    cql> CREATE KEYSPACE keyspace-name WITH replication = {'class' : 'SimpleStrategy','replication_factor' : 1};
    

    (keyspace-name is the name you have chosen for the keyspace)

  4. At this point, you may elect to create the database tables. (Alternatively, you can exit CQL and create the tables using the kea-admin tool, as explained below) To do this:

    cqslh -k keyspace-name -f path-to-kea/share/kea/scripts/cql/dhcpdb_create.cql
    

    (path-to-kea is the location where you installed Kea)

If you elected not to create the tables in step 4, you can do so now by running the kea-admin tool:

$ kea-admin lease-init cql -n database-name

(Do not do this if you did create the tables in step 4.) kea-admin implements rudimentary checks: it will refuse to initialize a database that contains any existing tables. If you want to start from scratch, you must remove all data manually. (This process is a manual operation on purpose to avoid possibly irretrievable mistakes by kea-admin)

4.3.4.2. Upgrading a CQL Database from an Earlier Version of Kea

Sometimes a new Kea version may use newer database schema, so there will be a need to upgrade the existing database. This can be done using the kea-admin lease-upgrade command.

To check the current version of the database, use the following command:

$ kea-admin lease-version cql -n database-name

(See Section 4.1, “Databases and Database Version Numbers†for a discussion about versioning) If the version does not match the minimum required for the new version of Kea (as described in the release notes), the database needs to be upgraded.

Before upgrading, please make sure that the database is backed up. The upgrade process does not discard any data but, depending on the nature of the changes, it may be impossible to subsequently downgrade to an earlier version. To perform an upgrade, issue the following command:

$ kea-admin lease-upgrade cql -n database-name

4.3.5. Using Read-Only Databases with Host Reservations

If a read-only database is used for storing host reservations, Kea must be explicitly configured to operate on the database in read-only mode. Sections Section 7.2.3.2, “Using Read-Only Databases for Host Reservations†and Section 8.2.3.2, “Using Read-Only Databases for Host Reservations†describe when such configuration may be reqired and how to configure Kea to operate using a read-only host database.

4.3.6. Limitations Related to the use of SQL Databases

The lease expiration time is stored in the SQL database for each lease as a timestamp value. Kea developers observed that MySQL database doesn't accept timestamps beyond 2147483647 seconds (maximum signed 32-bit number) from the beginning of the epoch. At the same time, some versions of PostgreSQL do accept greater values but the value is altered when it is read back. For this reason the lease database backends put the restriction for the maximum timestamp to be stored in the database, which is equal to the maximum signed 32-bit number. This effectively means that the current Kea version can't store the leases which expiration time is later than 2147483647 seconds since the beginning of the epoch (around year 2038). This will be fixed when the database support for longer timestamps is available.

Chapter 5. Kea Configuration

Kea is designed to allow different methods by which it can be configured, each method being implemented by a component known as a configuration backend. At present, only one such backend is available, that allowing configuration by means of a JSON file.

5.1. JSON Configuration Backend

JSON is the default configuration backend. It assumes that the servers are started from the command line (either directly or using a script, e.g. keactrl). The JSON backend uses certain signals to influence Kea. The configuration file is specified upon startup using the -c parameter.

5.1.1. JSON Syntax

Configuration files for DHCPv4, DHCPv6 and DDNS modules are defined in an extended JSON format. Basic JSON is defined in RFC 4627. Kea components use a slightly modified form of JSON in that they allow shell-style comments in the file: lines with the hash (#) character in the first column are comment lines and are ignored.

The configuration file consists of a single object (often colloquially called a map) started with a curly bracket. It comprises the "Dhcp4", "Dhcp6", "DhcpDdns" and/or "Logging" objects. It is possible to define additional elements, but they will be ignored. For example, it is possible to define Dhcp4, Dhcp6 and Logging elements in a single configuration file that can be used to start both the DHCPv4 and DHCPv6 components. When starting, the DHCPv4 component will use Dhcp4 object to configure itself and the Logging object to configure logging parameters; it will ignore the Dhcp6 object.

A very simple configuration for both DHCPv4 and DHCPv6 could look like this:

# The whole configuration starts here.
{

# DHCPv4 specific configuration starts here.
"Dhcp4": {
    "interfaces-config": {
        "interfaces": [ "eth0" ],
        "dhcp-socket-type": "raw"
    },
    "valid-lifetime": 4000,
    "renew-timer": 1000,
    "rebind-timer": 2000,
    "subnet4": [{
       "pools": [ { "pool": "192.0.2.1-192.0.2.200" } ],
       "subnet": "192.0.2.0/24"
    }]
},
# DHCPv4 specific configuration ends here.

# DHCPv6 specific configuration starts here.
"Dhcp6": {
    "interfaces-config": {
        "interfaces": [ "eth1" ]
    },
    "preferred-lifetime": 3000,
    "valid-lifetime": 4000,
    "renew-timer": 1000,
    "rebind-timer": 2000,
    "subnet6": [{
       "pools": [ { "pool": "2001:db8::/80" } ],
       "subnet": "2001:db8::/64"
    }]
},
# DHCPv6 specific configuration ends here.

# Logger parameters (that could be shared among several components) start here.
# This section is used by both the DHCPv4 and DHCPv6 servers.
"Logging": {
   "loggers": [{
        "name": "*",
        "severity": "DEBUG"
    }]
}
# Logger parameters end here.

# The whole configuration structure ends here.
}

More examples are available in the installed share/doc/kea/examples directory.

To avoid repetition of mostly similar structures, examples in the rest of this guide will showcase only the subset of parameters appropriate for a given context. For example, when discussing the IPv6 subnets configuration in DHCPv6, only subnet6 parameters will be mentioned. It is implied that the remaining elements (the global map that holds Dhcp6, Logging and possibly DhcpDdns) are present, but they are omitted for clarity. Usually, locations where extra parameters may appear are denoted by an ellipsis.

5.1.2. Simplified Notation

It is sometimes convenient to refer to a specific element in the configuration hierarchy. Each hierarchy level is separated by a slash. If there is an array, a specific instance within that array is referenced by a number in square brackets (with numbering starting at zero). For example, in the above configuration the valid-lifetime in the Dhcp6 component can be referred to as Dhcp6/valid-lifetime and the pool in the first subnet defined in the DHCPv6 configuration as Dhcp6/subnet6[0]/pool.

Chapter 6. Managing Kea with keactrl

6.1. Overview

keactrl is a shell script which controls the startup, shutdown and reconfiguration of the Kea servers (kea-dhcp4, kea-dhcp6 and kea-dhcp-ddns). It also provides the means for checking the current status of the servers and determining the configuration files in use.

6.2. Command Line Options

keactrl is run as follows:

keactrl <command> [-c keactrl-config-file] [-s server[,server,..]]

<command> is the one of the commands described in Section 6.4, “Commandsâ€.

The optional -c keactrl-config-file switch allows specification of an alternate keactrl configuration file. (--ctrl-config is a synonym for -c.) In the absence of -c, keactrl will use the default configuration file [kea-install-dir]/etc/kea/keactrl.conf.

The optional -s server[,server ...] switch selects the servers to which the command is issued. (--server is a synonym for -s.) If absent, the command is sent to all servers enabled in the keactrl configuration file. If multiple servers are specified, they should be separated by commas with no intervening spaces.

6.3. The keactrl Configuration File

Depending on requirements, not all of the available servers need be run. The keactrl configuration file sets which servers are enabled and which are disabled. The default configuration file is [kea-install-dir]/etc/kea/keactrl.conf, but this can be overridden on a per-command basis using the -c switch.

The contents of keactrl.conf are:

# This is a configuration file for keactrl script which controls
# the startup, shutdown, reconfiguration and gathering the status
# of the Kea servers.

# prefix holds the location where the Kea is installed.
prefix=/usr/local

# Location of Kea configuration file.
kea_config_file=${prefix}/etc/kea/kea.conf

# Location of Kea binaries.
exec_prefix=${prefix}
dhcp4_srv=${exec_prefix}/sbin/kea/kea-dhcp4
dhcp6_srv=${exec_prefix}/sbin/kea/kea-dhcp6
dhcp_ddns_srv=${exec_prefix}/sbin/kea/kea-dhcp-ddns

# Start DHCPv4 server?
dhcp4=yes

# Start DHCPv6 server?
dhcp6=yes

# Start DHCP DDNS server?
dhcp_ddns=yes

# Be verbose?
kea_verbose=no

The dhcp4, dhcp6 and dhcp_ddns parameters set to "yes" configure keactrl to manage (start, reconfigure) all servers, i.e. kea-dhcp4, kea-dhcp6 and kea-dhcp-ddns. When any of these parameters is set to "no" the keactrl will ignore the corresponding server when starting or reconfiguring Kea.

By default, Kea servers managed by keactrl are located in [kea-install-dir]/sbin. This should work for most installations. If the default location needs to be altered for any reason, the paths specified with the dhcp4_srv, dhcp6_srv and dhcp_ddns_srv parameters should be modified.

The kea_verbose parameter specifies the verbosity of the servers being started. When kea_verbose is set to "yes" the logging level of the server is set to DEBUG. Modification of the logging severity in a configuration file, as described in Chapter 17, Logging, will have no effect as long as the kea_verbose is set to "yes". Setting it to "no" will cause the server to use the logging levels specified in the Kea configuration file for respective loggers. If no logging configuration is specified, the default settings will be used.

Note

The verbosity for the server is set when it is started. Once started, the verbosity can be only changed by stopping the server and starting it again with the new value of the kea_verbose parameter.

6.4. Commands

The following commands are supported by keactrl:

  • start - starts selected servers.
  • stop - stops all running servers.
  • reload - triggers reconfiguration of the selected servers by sending the SIGHUP signal to them.
  • status - returns the status of the servers (active or inactive) and the names of the configuration files in use.

Typical output from keactrl when starting the servers looks similar to the following:

$ keactrl start
INFO/keactrl: Starting kea-dhcp4 -c /usr/local/etc/kea/kea.conf -d
INFO/keactrl: Starting kea-dhcp6 -c /usr/local/etc/kea/kea.conf -d
INFO/keactrl: Starting kea-dhcp-ddns -c /usr/local/etc/kea/kea.conf -d

Kea's servers create PID files upon startup. These files are used by keactrl to determine whether or not a given server is running. If one or more servers are running when the start command is issued, the output will look similar to the following:

$ keactrl start
INFO/keactrl: kea-dhcp4 appears to be running, see: PID 10918, PID file: /usr/local/var/kea/kea.kea-dhcp4.pid.
INFO/keactrl: kea-dhcp6 appears to be running, see: PID 10924, PID file: /usr/local/var/kea/kea.kea-dhcp6.pid.
INFO/keactrl: kea-dhcp-ddns appears to be running, see: PID 10930, PID file: /usr/local/var/kea/kea.kea-dhcp-ddns.pid.

During normal shutdowns these PID files are deleted. They may, however, be left over as remnants following a system crash. It is possible, though highly unlikely, that upon system restart the PIDs they contain actually refer to processes unrelated to Kea. This condition will cause keactrl to decide that the servers are running, when in fact they are not. In such a case the PID files as listed in the keactrl output must be manually deleted.

The following command stops all servers:

$ keactrl stop
INFO/keactrl: Stopping kea-dhcp4...
INFO/keactrl: Stopping kea-dhcp6...
INFO/keactrl: Stopping kea-dhcp-ddns...

Note that the stop will attempt to stop all servers regardless of whether they are "enabled" in the keactrl.conf. If any of the servers are not running, an informational message is displayed as in the stop command output below.

$ keactrl stop
INFO/keactrl: kea-dhcp4 isn't running.
INFO/keactrl: kea-dhcp6 isn't running.
INFO/keactrl: kea-dhcp-ddns isn't running.

As already mentioned, the reconfiguration of each Kea server is triggered by the SIGHUP signal. The reload command sends the SIGHUP signal to the servers that are enabled in the keactrl configuration file and are currently running. When a server receives the SIGHUP signal it re-reads its configuration file and, if the new configuration is valid, uses the new configuration. A reload is executed as follows:

$ keactrl reload
INFO/keactrl: Reloading kea-dhcp4...
INFO/keactrl: Reloading kea-dhcp6...
INFO/keactrl: Reloading kea-dhcp-ddns...

If any of the servers are not running, an informational message is displayed as in the reload command output below.

$ keactrl stop
INFO/keactrl: kea-dhcp4 isn't running.
INFO/keactrl: kea-dhcp6 isn't running.
INFO/keactrl: kea-dhcp-ddns isn't running.

Note

Currently keactrl does not report configuration failures when the server is started or reconfigured. To check if the server's configuration succeeded the Kea log must be examined for errors. By default, this is written to the syslog file.

Sometimes it is useful to check which servers are running. The status reports this, typical output looking like:

$ keactrl status
DHCPv4 server: active
DHCPv6 server: inactive
DHCP DDNS: active
Kea configuration file: /usr/local/etc/kea/kea.conf
keactrl configuration file: /usr/local/etc/kea/keactrl.conf

6.5. Overriding the Server Selection

The optional -s switch allows the selection of the servers to which keactrl command is issued. For example, the following instructs keactrl to stop the kea-dhcp4 and kea-dhcp6 servers and leave the kea-dhcp-ddns server running:

$ keactrl stop -s dhcp4,dhcp6

Similarly, the following will only start the kea-dhcp4 and kea-dhcp-ddns servers and not kea-dhcp6.

$ keactrl start -s dhcp4,dhcp_ddns

Note that the behavior of the -s switch with the start and reload commands is different to its behavior with the stop command. On start and reload, keactrl will check if the servers given as parameters to the -s switch are enabled in the keactrl configuration file: if not, the server will be ignored. For stop however, this check is not made: the command is applied to all listed servers, regardless of whether they have been enabled in the file.

The following keywords can be used with the -s command line option:

  • dhcp4 for kea-dhcp4.
  • dhcp6 for kea-dhcp6.
  • dhcp_ddns for kea-dhcp-ddns.
  • all for all servers (default).

Chapter 7. The DHCPv4 Server

Table of Contents

7.1. Starting and Stopping the DHCPv4 Server
7.2. DHCPv4 Server Configuration
7.2.1. Introduction
7.2.2. Lease Storage
7.2.3. Hosts Storage
7.2.4. Interface Configuration
7.2.5. Issues with Unicast Responses to DHCPINFORM
7.2.6. IPv4 Subnet Identifier
7.2.7. Configuration of IPv4 Address Pools
7.2.8. Standard DHCPv4 Options
7.2.9. Custom DHCPv4 options
7.2.10. DHCPv4 Vendor Specific Options
7.2.11. Nested DHCPv4 Options (Custom Option Spaces)
7.2.12. Unspecified Parameters for DHCPv4 Option Configuration
7.2.13. Stateless Configuration of DHCPv4 Clients
7.2.14. Client Classification in DHCPv4
7.2.15. DDNS for DHCPv4
7.2.16. Next Server (siaddr)
7.2.17. Echoing Client-ID (RFC 6842)
7.2.18. Using Client Identifier and Hardware Address
7.2.19. DHCPv4-over-DHCPv6: DHCPv4 Side
7.3. Host Reservation in DHCPv4
7.3.1. Address Reservation Types
7.3.2. Conflicts in DHCPv4 Reservations
7.3.3. Reserving a Hostname
7.3.4. Including Specific DHCPv4 Options in Reservations
7.3.5. Reserving Next Server, Server Hostname and Boot File Name
7.3.6. Reserving Client Classes in DHCPv4
7.3.7. Storing Host Reservations in MySQL or PostgreSQL
7.3.8. Storing host reservations in CQL (Cassandra)
7.3.9. Fine Tuning DHCPv4 Host Reservation
7.4. Server Identifier in DHCPv4
7.5. How the DHCPv4 Server Selects a Subnet for the Client
7.5.1. Using a Specific Relay Agent for a Subnet
7.5.2. Segregating IPv4 Clients in a Cable Network
7.6. Duplicate Addresses (DHCPDECLINE Support)
7.7. Statistics in the DHCPv4 Server
7.8. Management API for the DHCPv4 Server
7.9. Supported DHCP Standards
7.10. DHCPv4 Server Limitations

7.1. Starting and Stopping the DHCPv4 Server

It is recommended that the Kea DHCPv4 server be started and stopped using keactrl (described in Chapter 6, Managing Kea with keactrl). However, it is also possible to run the server directly: it accepts the following command-line switches:

  • -c file - specifies the configuration file. This is the only mandatory switch.
  • -d - specifies whether the server logging should be switched to debug/verbose mode. In verbose mode, the logging severity and debuglevel specified in the configuration file are ignored and "debug" severity and the maximum debuglevel (99) are assumed. The flag is convenient, for temporarily switching the server into maximum verbosity, e.g. when debugging.
  • -p port - specifies UDP port on which the server will listen. This is only useful during testing, as a DHCPv4 server listening on ports other than the standard ones will not be able to handle regular DHCPv4 queries.
  • -v - prints out the Kea version and exits.
  • -V - prints out the Kea extended version with additional parameters and exits. The listing includes the versions of the libraries dynamically linked to Kea.
  • -W - prints out the Kea configuration report and exits. The report is a copy of the config.report file produced by ./configure: it is embedded in the executable binary.

The config.report may also be accessed more directly. The following command may be used to extract this information. The binary path may be found in the install directory or in the .libs subdirectory in the source tree. For example kea/src/bin/dhcp4/.libs/kea-dhcp4.

strings path/kea-dhcp4 | sed -n 's/;;;; //p'

On start-up, the server will detect available network interfaces and will attempt to open UDP sockets on all interfaces mentioned in the configuration file. Since the DHCPv4 server opens privileged ports, it requires root access. Make sure you run this daemon as root.

During startup the server will attempt to create a PID file of the form: localstatedir]/[conf name].kea-dhcp6.pid where:

  • localstatedir: The value as passed into the build configure script. It defaults to "/usr/local/var". (Note that this value may be overridden at run time by setting the environment variable KEA_PIDFILE_DIR. This is intended primarily for testing purposes.)
  • conf name: The configuration file name used to start the server, minus all preceding path and file extension. For example, given a pathname of "/usr/local/etc/kea/myconf.txt", the portion used would be "myconf".

If the file already exists and contains the PID of a live process, the server will issue a DHCP4_ALREADY_RUNNING log message and exit. It is possible, though unlikely, that the file is a remnant of a system crash and the process to which the PID belongs is unrelated to Kea. In such a case it would be necessary to manually delete the PID file.

The server can be stopped using the kill command. When running in a console, the server can also be shut down by pressing ctrl-c. It detects the key combination and shuts down gracefully.

7.2. DHCPv4 Server Configuration

7.2.1. Introduction

This section explains how to configure the DHCPv4 server using the Kea configuration backend. (Kea configuration using any other backends is outside of scope of this document.) Before DHCPv4 is started, its configuration file has to be created. The basic configuration is as follows:

{
# DHCPv4 configuration starts in this line
"Dhcp4": {

# First we set up global values
    "valid-lifetime": 4000,
    "renew-timer": 1000,
    "rebind-timer": 2000,

# Next we setup the interfaces to be used by the server.
    "interfaces-config": {
        "interfaces": [ "eth0" ]
    },

# And we specify the type of lease database
    "lease-database": {
        "type": "memfile",
        "persist": true,
        "name": "/var/kea/dhcp4.leases"
    },

# Finally, we list the subnets from which we will be leasing addresses.
    "subnet4": [
        {
            "subnet": "192.0.2.0/24",
            "pools": [
                {
                     "pool": "192.0.2.1 - 192.0.2.200"
                }
            ]
        }
    ]
# DHCPv4 configuration ends with the next line
}

} 

The following paragraphs provide a brief overview of the parameters in the above example together with their format. Subsequent sections of this chapter go into much greater detail for these and other parameters.

The lines starting with a hash (#) are comments and are ignored by the server; they do not impact its operation in any way.

The configuration starts in the first line with the initial opening curly bracket (or brace). Each configuration consists of one or more objects. In this specific example, we have only one object, called Dhcp4. This is a simplified configuration, as usually there will be additional objects, like Logging or DhcpDns, but we omit them now for clarity. The Dhcp4 configuration starts with the "Dhcp4": { line and ends with the corresponding closing brace (in the above example, the brace after the last comment). Everything defined between those lines is considered to be the Dhcp4 configuration.

In the general case, the order in which those parameters appear does not matter. There are two caveats here though. The first one is to remember that the configuration file must be well formed JSON. That means that the parameters for any given scope must be separated by a comma and there must not be a comma after the last parameter. When reordering a configuration file, keep in mind that moving a parameter to or from the last position in a given scope may also require moving the comma. The second caveat is that it is uncommon — although legal JSON — to repeat the same parameter multiple times. If that happens, the last occurrence of a given parameter in a given scope is used while all previous instances are ignored. This is unlikely to cause any confusion as there are no real life reasons to keep multiple copies of the same parameter in your configuration file.

Moving onto the DHCPv4 configuration elements, the first few elements define some global parameters. valid-lifetime defines for how long the addresses (leases) given out by the server are valid. If nothing changes, a client that got an address is allowed to use it for 4000 seconds. (Note that integer numbers are specified as is, without any quotes around them.) renew-timer and rebind-timer are values (also in seconds) that define T1 and T2 timers that govern when the client will begin the renewal and rebind procedures. Note that renew-timer and rebind-timer are optional. If they are not specified the client will select values for T1 and T2 timers according to the RFC 2131.

The interfaces-config map specifies the server configuration concerning the network interfaces, on which the server should listen to the DHCP messages. The interfaces parameter specifies a list of network interfaces on which the server should listen. Lists are opened and closed with square brackets, with elements separated by commas. Had we wanted to listen on two interfaces, the interfaces-config would look like this:

"interfaces-config": {
    "interfaces": [ "eth0", "eth1" ]
},

The next couple of lines define the lease database, the place where the server stores its lease information. This particular example tells the server to use memfile, which is the simplest (and fastest) database backend. It uses an in-memory database and stores leases on disk in a CSV file. This is a very simple configuration. Usually the lease database configuration is more extensive and contains additional parameters. Note that lease-database is an object and opens up a new scope, using an opening brace. Its parameters (just one in this example - type) follow. Had there been more than one, they would be separated by commas. This scope is closed with a closing brace. As more parameters for the Dhcp4 definition follow, a trailing comma is present.

Finally, we need to define a list of IPv4 subnets. This is the most important DHCPv4 configuration structure as the server uses that information to process clients' requests. It defines all subnets from which the server is expected to receive DHCP requests. The subnets are specified with the subnet4 parameter. It is a list, so it starts and ends with square brackets. Each subnet definition in the list has several attributes associated with it, so it is a structure and is opened and closed with braces. At a minimum, a subnet definition has to have at least two parameters: subnet (that defines the whole subnet) and pools (which is a list of dynamically allocated pools that are governed by the DHCP server).

The example contains a single subnet. Had more than one been defined, additional elements in the subnet4 parameter would be specified and separated by commas. For example, to define three subnets, the following syntax would be used:

"subnet4": [
    {
        "pools": [ { "pool":  "192.0.2.1 - 192.0.2.200" } ],
        "subnet": "192.0.2.0/24"
    },
    {
        "pools": [ { "pool": "192.0.3.100 - 192.0.3.200" } ],
        "subnet": "192.0.3.0/24"
    },
    {
        "pools": [ { "pool": "192.0.4.1 - 192.0.4.254" } ],
        "subnet": "192.0.4.0/24"
    }
]

Note that indentation is optional and is used for aesthetic purposes only. In some cases in may be preferable to use more compact notation.

After all the parameters have been specified, we have two contexts open: global and Dhcp4, hence we need two closing curly brackets to close them. In a real life configuration file there most likely would be additional components defined such as Logging or DhcpDdns, so the closing brace would be followed by a comma and another object definition.

7.2.2. Lease Storage

All leases issued by the server are stored in the lease database. Currently there are four database backends available: memfile (which is the default backend), MySQL, PostgreSQL and Cassandra.

7.2.2.1. Memfile - Basic Storage for Leases

The server is able to store lease data in different repositories. Larger deployments may elect to store leases in a database. Section 7.2.2.2, “Lease Database Configuration†describes this option. In typical smaller deployments though, the server will store lease information in a CSV file rather than a database. As well as requiring less administration, an advantage of using a file for storage is that it eliminates a dependency on third-party database software.

The configuration of the file backend (Memfile) is controlled through the Dhcp4/lease-database parameters. The type parameter is mandatory and it specifies which storage for leases the server should use. The value of "memfile" indicates that the file should be used as the storage. The following list gives additional, optional, parameters that can be used to configure the Memfile backend.

  • persist: controls whether the new leases and updates to existing leases are written to the file. It is strongly recommended that the value of this parameter is set to true at all times, during the server's normal operation. Not writing leases to disk will mean that if a server is restarted (e.g. after a power failure), it will not know what addresses have been assigned. As a result, it may hand out addresses to new clients that are already in use. The value of false is mostly useful for performance testing purposes. The default value of the persist parameter is true, which enables writing lease updates to the lease file.
  • name: specifies an absolute location of the lease file in which new leases and lease updates will be recorded. The default value for this parameter is "[kea-install-dir]/var/kea/kea-leases4.csv" .
  • lfc-interval: specifies the interval in seconds, at which the server will perform a lease file cleanup (LFC). This removes redundant (historical) information from the lease file and effectively reduces the lease file size. The cleanup process is described in more detailed fashion further in this section. The default value of the lfc-interval is 0, which disables the LFC.

An example configuration of the Memfile backend is presented below:

"Dhcp4": {
    "lease-database": {
        "type": "memfile",
        "persist": true,
        "name": "/tmp/kea-leases4.csv",
        "lfc-interval": 1800
    }
}

This configuration selects the /tmp/kea-leases4.csv as the storage for lease information and enables persistence (writing lease updates to this file). It also configures the backend perform the periodic cleanup of the lease files, executed every 30 minutes.

It is important to know how the lease file contents are organized to understand why the periodic lease file cleanup is needed. Every time the server updates a lease or creates a new lease for the client, the new lease information must be recorded in the lease file. For performance reasons, the server does not update the existing client's lease in the file, as it would potentially require rewriting the entire file. Instead, it simply appends the new lease information to the end of the file: the previous lease entries for the client are not removed. When the server loads leases from the lease file, e.g. at the server startup, it assumes that the latest lease entry for the client is the valid one. The previous entries are discarded. This means that the server can re-construct the accurate information about the leases even though there may be many lease entries for each client. However, storing many entries for each client results in bloated lease file and impairs the performance of the server's startup and reconfiguration as it needs to process a larger number of lease entries.

Lease file cleanup (LFC) removes all previous entries for each client and leaves only the latest ones. The interval at which the cleanup is performed is configurable, and it should be selected according to the frequency of lease renewals initiated by the clients. The more frequent the renewals, the smaller the value of lfc-interval should be. Note however, that the LFC takes time and thus it is possible (although unlikely) that new cleanup is started while the previous cleanup instance is still running, if the lfc-interval is too short. The server would recover from this by skipping the new cleanup when it detects that the previous cleanup is still in progress. But it implies that the actual cleanups will be triggered more rarely than configured. Moreover, triggering a new cleanup adds an overhead to the server which will not be able to respond to new requests for a short period of time when the new cleanup process is spawned. Therefore, it is recommended that the lfc-interval value is selected in a way that would allow for the LFC to complete the cleanup before a new cleanup is triggered.

Lease file cleanup is performed by a separate process (in background) to avoid a performance impact on the server process. In order to avoid the conflicts between two processes both using the same lease files, the LFC process operates on the copy of the original lease file, rather than on the lease file used by the server to record lease updates. There are also other files being created as a side effect of the lease file cleanup. The detailed description of the LFC is located on the Kea wiki: http://kea.isc.org/wiki/LFCDesign.

7.2.2.2. Lease Database Configuration

Note

Lease database access information must be configured for the DHCPv4 server, even if it has already been configured for the DHCPv6 server. The servers store their information independently, so each server can use a separate database or both servers can use the same database.

Lease database configuration is controlled through the Dhcp4/lease-database parameters. The type of the database must be set to "memfile", "mysql", "postgresql" or "cql", e.g.

"Dhcp4": { "lease-database": { "type": "mysql", ... }, ... }

Next, the name of the database to hold the leases must be set: this is the name used when the database was created (see Section 4.3.2.1, “First Time Creation of the MySQL Databaseâ€, Section 4.3.3.1, “First Time Creation of the PostgreSQL Database†or Section 4.3.4.1, “First Time Creation of the Cassandra Databaseâ€).

"Dhcp4": { "lease-database": { "name": "database-name" , ... }, ... }

If the database is located on a different system to the DHCPv4 server, the database host name must also be specified. (It should be noted that this configuration may have a severe impact on server performance.):

"Dhcp4": { "lease-database": { "host": remote-host-name, ... }, ... }

The usual state of affairs will be to have the database on the same machine as the DHCPv4 server. In this case, set the value to the empty string:

"Dhcp4": { "lease-database": { "host" : "", ... }, ... }

Should the database be located on a different system, you may need to specify a longer interval for the connection timeout:

"Dhcp4": { "lease-database": { "connect-timeout" : timeout-in-seconds, ... }, ... }

The default value of five seconds should be more than adequate for local connections. If a timeout is given though, it should be an integer greater than zero.

Finally, the credentials of the account under which the server will access the database should be set:

"Dhcp4": { "lease-database": { "user": "user-name",
                               "password": "password",
                              ... },
           ... }

If there is no password to the account, set the password to the empty string "". (This is also the default.)

7.2.3. Hosts Storage

Kea is also able to store information about host reservations in the database. The hosts database configuration uses the same syntax as the lease database. In fact, a Kea server opens independent connections for each purpose, be it lease or hosts information. This arrangement gives the most flexibility. Kea can be used to keep leases and host reservations separately, but can also point to the same database. Currently the supported hosts database types are MySQL and PostgreSQL. The Cassandra backend does not support host reservations yet.

Please note that usage of hosts storage is optional. A user can define all host reservations in the configuration file. That is the recommended way if the number of reservations is small. However, when the number of reservations grows it's more convenient to use host storage. Please note that both storage methods (configuration file and one of the supported databases) can be used together. If hosts are defined in both places, the definitions from the configuration file are checked first and external storage is checked later, if necessary.

7.2.3.1. DHCPv4 Hosts Database Configuration

Hosts database configuration is controlled through the Dhcp4/hosts-database parameters. If enabled, the type of the database must be set to "mysql" or "postgresql". Other hosts backends may be added in later versions of Kea.

"Dhcp4": { "hosts-database": { "type": "mysql", ... }, ... }

Next, the name of the database to hold the reservations must be set: this is the name used when the lease database was created (see Section 4.3, “Supported Databases†for instructions how to setup the desired database type).

"Dhcp4": { "hosts-database": { "name": "database-name" , ... }, ... }

If the database is located on a different system than the DHCPv4 server, the database host name must also be specified. (Again it should be noted that this configuration may have a severe impact on server performance.):

"Dhcp4": { "hosts-database": { "host": remote-host-name, ... }, ... }

The usual state of affairs will be to have the database on the same machine as the DHCPv4 server. In this case, set the value to the empty string:

"Dhcp4": { "hosts-database": { "host" : "", ... }, ... }

Finally, the credentials of the account under which the server will access the database should be set:

"Dhcp4": { "hosts-database": { "user": "user-name",
                               "password": "password",
                              ... },
           ... }

If there is no password to the account, set the password to the empty string "". (This is also the default.)

7.2.3.2. Using Read-Only Databases for Host Reservations

In some deployments the database user whose name is specified in the database backend configuration may not have write privileges to the database. This is often required by the policy within a given network to secure the data from being unintentionally modified. In many cases administrators have inventory databases deployed, which contain substantially more information about the hosts than static reservations assigned to them. The inventory database can be used to create a view of a Kea hosts database and such view is often read only.

Kea host database backends operate with an implicit configuration to both read from and write to the database. If the database user does not have write access to the host database, the backend will fail to start and the server will refuse to start (or reconfigure). However, if access to a read only host database is required for retrieving reservations for clients and/or assign specific addresses and options, it is possible to explicitly configure Kea to start in "read-only" mode. This is controlled by the readonly boolean parameter as follows:

"Dhcp4": { "hosts-database": { "readonly": true, ... }, ... }

Setting this parameter to false would configure the database backend to operate in "read-write" mode, which is also a default configuration if the parameter is not specified.

Note

The readonly parameter is currently only supported for MySQL and PostgreSQL databases.

7.2.4. Interface Configuration

The DHCPv4 server has to be configured to listen on specific network interfaces. The simplest network interface configuration tells the server to listen on all available interfaces:

"Dhcp4": {
    "interfaces-config": {
        "interfaces": [ "*" ]
    }
    ...
},
  

The asterisk plays the role of a wildcard and means "listen on all interfaces". However, it is usually a good idea to explicitly specify interface names:

"Dhcp4": {
    "interfaces-config": {
        "interfaces": [ "eth1", "eth3" ]
    },
    ...
}
  

It is possible to use wildcard interface name (asterisk) concurrently with explicit interface names:

"Dhcp4": {
    "interfaces-config": {
        "interfaces": [ "eth1", "eth3", "*" ]
    },
    ...
}
  

It is anticipated that this form of usage will only be used when it is desired to temporarily override a list of interface names and listen on all interfaces.

Some deployments of DHCP servers require that the servers listen on the interfaces with multiple IPv4 addresses configured. In these situations, the address to use can be selected by appending an IPv4 address to the interface name in the following manner:

"Dhcp4": {
    "interfaces-config": {
        "interfaces": [ "eth1/10.0.0.1", "eth3/192.0.2.3" ]
    },
    ...
}
  

Should the server be required to listen on multiple IPv4 addresses assigned to the same interface, multiple addresses can be specified for an interface as in the example below:

"Dhcp4": {
    "interfaces-config": {
        "interfaces": [ "eth1/10.0.0.1", "eth1/10.0.0.2" ]
    },
    ...
}
  

Alternatively, if the server should listen on all addresses for the particular interface, an interface name without any address should be specified.

Kea supports responding to directly connected clients which don't have an address configured. This requires that the server injects the hardware address of the destination into the data link layer of the packet being sent to the client. The DHCPv4 server utilizes the raw sockets to achieve this, and builds the entire IP/UDP stack for the outgoing packets. The down side of raw socket use, however, is that incoming and outgoing packets bypass the firewalls (e.g. iptables). It is also troublesome to handle traffic on multiple IPv4 addresses assigned to the same interface, as raw sockets are bound to the interface and advanced packet filtering techniques (e.g. using the BPF) have to be used to receive unicast traffic on the desired addresses assigned to the interface, rather than capturing whole traffic reaching the interface to which the raw socket is bound. Therefore, in the deployments where the server doesn't have to provision the directly connected clients and only receives the unicast packets from the relay agents, the DHCP server should be configured to utilize IP/UDP datagram sockets instead of raw sockets. The following configuration demonstrates how this can be achieved:

"Dhcp4": {
    "interfaces-config": {
        "interfaces": [ "eth1", "eth3" ],
        "dhcp-socket-type": "udp"
    },
    ...
}
  

The dhcp-socket-type specifies that the IP/UDP sockets will be opened on all interfaces on which the server listens, i.e. "eth1" and "eth3" in our case. If the dhcp-socket-type is set to raw, it configures the server to use raw sockets instead. If the dhcp-socket-type value is not specified, the default value raw is used.

Using UDP sockets automatically disables the reception of broadcast packets from directly connected clients. This effectively means that the UDP sockets can be used for relayed traffic only. When using the raw sockets, both the traffic from the directly connected clients and the relayed traffic will be handled. Caution should be taken when configuring the server to open multiple raw sockets on the interface with several IPv4 addresses assigned. If the directly connected client sends the message to the broadcast address all sockets on this link will receive this message and multiple responses will be sent to the client. Hence, the configuration with multiple IPv4 addresses assigned to the interface should not be used when the directly connected clients are operating on that link. To use a single address on such interface, the "interface-name/address" notation should be used.

Note

Specifying the value raw as the socket type, doesn't guarantee that the raw sockets will be used! The use of raw sockets to handle the traffic from the directly connected clients is currently supported on Linux and BSD systems only. If the raw sockets are not supported on the particular OS, the server will issue a warning and fall back to use IP/UDP sockets.

7.2.5. Issues with Unicast Responses to DHCPINFORM

The use of UDP sockets has certain benefits in deployments where the server receives only relayed traffic; these benefits are mentioned in Section 7.2.4, “Interface Configurationâ€. From the administrator's perspective it is often desirable to configure the system's firewall to filter out the unwanted traffic, and the use of UDP sockets facilitates this. However, the administrator must also be aware of the implications related to filtering certain types of traffic as it may impair the DHCP server's operation.

In this section we are focusing on the case when the server receives the DHCPINFORM message from the client via a relay. According to RFC 2131, the server should unicast the DHCPACK response to the address carried in the "ciaddr" field. When the UDP socket is in use, the DHCP server relies on the low level functions of an operating system to build the data link, IP and UDP layers of the outgoing message. Typically, the OS will first use ARP to obtain the client's link layer address to be inserted into the frame's header, if the address is not cached from a previous transaction that the client had with the server. When the ARP exchange is successful, the DHCP message can be unicast to the client, using the obtained address.

Some system administrators block ARP messages in their network, which causes issues for the server when it responds to the DHCPINFORM messages, because the server is unable to send the DHCPACK if the preceding ARP communication fails. Since the OS is entirely responsible for the ARP communication and then sending the DHCP packet over the wire, the DHCP server has no means to determine that the ARP exchange failed and the DHCP response message was dropped. Thus, the server does not log any error messages when the outgoing DHCP response is dropped. At the same time, all hooks pertaining to the packet sending operation will be called, even though the message never reaches its destination.

Note that the issue described in this section is not observed when the raw sockets are in use, because, in this case, the DHCP server builds all the layers of the outgoing message on its own and does not use ARP. Instead, it inserts the value carried in the 'chaddr' field of the DHCPINFORM message into the link layer.

Server administrators willing to support DHCPINFORM messages via relays should not block ARP traffic in their networks or should use raw sockets instead of UDP sockets.

7.2.6. IPv4 Subnet Identifier

The subnet identifier is a unique number associated with a particular subnet. In principle, it is used to associate clients' leases with their respective subnets. When a subnet identifier is not specified for a subnet being configured, it will be automatically assigned by the configuration mechanism. The identifiers are assigned from 1 and are monotonically increased for each subsequent subnet: 1, 2, 3 ....

If there are multiple subnets configured with auto-generated identifiers and one of them is removed, the subnet identifiers may be renumbered. For example: if there are four subnets and the third is removed the last subnet will be assigned the identifier that the third subnet had before removal. As a result, the leases stored in the lease database for subnet 3 are now associated with subnet 4, something that may have unexpected consequences. It is planned to implement a mechanism to preserve auto-generated subnet ids in a future version of Kea. However, the only remedy for this issue at present is to manually specify a unique identifier for each subnet.

The following configuration will assign the specified subnet identifier to the newly configured subnet:

"Dhcp4": {
    "subnet4": [
        {
            "subnet": "192.0.2.0/24",
            "id": 1024,
            ...
        }
    ]
}

This identifier will not change for this subnet unless the "id" parameter is removed or set to 0. The value of 0 forces auto-generation of the subnet identifier.

7.2.7. Configuration of IPv4 Address Pools

The main role of a DHCPv4 server is address assignment. For this, the server has to be configured with at least one subnet and one pool of dynamic addresses for it to manage. For example, assume that the server is connected to a network segment that uses the 192.0.2.0/24 prefix. The Administrator of that network has decided that addresses from range 192.0.2.10 to 192.0.2.20 are going to be managed by the Dhcp4 server. Such a configuration can be achieved in the following way:

"Dhcp4": {
    "subnet4": [
        {
            "subnet": "192.0.2.0/24",
            "pools": [
                { "pool": "192.0.2.10 - 192.0.2.20" }
            ],
            ...
        }
    ]
}

Note that subnet is defined as a simple string, but the pools parameter is actually a list of pools: for this reason, the pool definition is enclosed in square brackets, even though only one range of addresses is specified.

Each pool is a structure that contains the parameters that describe a single pool. Currently there is only one parameter, pool, which gives the range of addresses in the pool. Additional parameters will be added in future releases of Kea.

It is possible to define more than one pool in a subnet: continuing the previous example, further assume that 192.0.2.64/26 should be also be managed by the server. It could be written as 192.0.2.64 to 192.0.2.127. Alternatively, it can be expressed more simply as 192.0.2.64/26. Both formats are supported by Dhcp4 and can be mixed in the pool list. For example, one could define the following pools:

"Dhcp4": {
    "subnet4": [
        {
            "subnet": "192.0.2.0/24",
            "pools": [
                { "pool": "192.0.2.10-192.0.2.20" },
                { "pool": "192.0.2.64/26" }
            ],
            ...
        }
    ],
    ...
}

White space in pool definitions is ignored, so spaces before and after the hyphen are optional. They can be used to improve readability.

The number of pools is not limited, but for performance reasons it is recommended to use as few as possible.

The server may be configured to serve more than one subnet:

"Dhcp4": {
    "subnet4": [
        {
            "subnet": "192.0.2.0/24",
            "pools": [ { "pool": "192.0.2.1 - 192.0.2.200" } ],
            ...
        },
        {
            "subnet": "192.0.3.0/24",
            "pools": [ { "pool": "192.0.3.100 - 192.0.3.200" } ],
            ...
        },
        {
            "subnet": "192.0.4.0/24",
            "pools": [ { "pool": "192.0.4.1 - 192.0.4.254" } ],
            ...
        }
    ]
}

When configuring a DHCPv4 server using prefix/length notation, please pay attention to the boundary values. When specifying that the server can use a given pool, it will also be able to allocate the first (typically network address) and the last (typically broadcast address) address from that pool. In the aforementioned example of pool 192.0.3.0/24, both 192.0.3.0 and 192.0.3.255 addresses may be assigned as well. This may be invalid in some network configurations. If you want to avoid this, please use the "min-max" notation.

7.2.8. Standard DHCPv4 Options

One of the major features of the DHCPv4 server is to provide configuration options to clients. Most of the options are sent by the server only if the client explicitly requests them using the Parameter Request List option. Those that do not require inclusion in the Parameter Request List option are commonly used options, e.g. "Domain Server", and options which require special behavior, e.g. "Client FQDN" is returned to the client if the client has included this option in its message to the server.

Table 7.1, “List of standard DHCPv4 options†comprises the list of the standard DHCPv4 options whose values can be configured using the configuration structures described in this section. This table excludes the options which require special processing and thus cannot be configured with some fixed values. The last column of the table indicates which options can be sent by the server even when they are not requested in the Parameter Request list option, and those which are sent only when explicitly requested.

The following example shows how to configure the addresses of DNS servers, which is one of the most frequently used options. Options specified in this way are considered global and apply to all configured subnets.

"Dhcp4": {
    "option-data": [
        {
           "name": "domain-name-servers",
           "code": 6,
           "space": "dhcp4",
           "csv-format": true,
           "data": "192.0.2.1, 192.0.2.2"
        },
        ...
    ]
}

The name parameter specifies the option name. For a list of currently supported names, see Table 7.1, “List of standard DHCPv4 options†below. The code parameter specifies the option code, which must match one of the values from that list. The next line specifies the option space, which must always be set to "dhcp4" as these are standard DHCPv4 options. For other option spaces, including custom option spaces, see Section 7.2.11, “Nested DHCPv4 Options (Custom Option Spaces)â€. The next line specifies the format in which the data will be entered: use of CSV (comma separated values) is recommended. The sixth line gives the actual value to be sent to clients. Data is specified as normal text, with values separated by commas if more than one value is allowed.

Options can also be configured as hexadecimal values. If csv-format is set to false, option data must be specified as a hexadecimal string. The following commands configure the domain-name-servers option for all subnets with the following addresses: 192.0.3.1 and 192.0.3.2. Note that csv-format is set to false.

"Dhcp4": {
    "option-data": [
        {
            "name": "domain-name-servers",
            "code": 6,
            "space": "dhcp4",
            "csv-format": false,
            "data": "C0 00 03 01 C0 00 03 02"
        },
        ...
    ],
    ...
}

Most of the parameters in the "option-data" structure are optional and can be omitted in some circumstances as discussed in the Section 7.2.12, “Unspecified Parameters for DHCPv4 Option Configurationâ€.

It is possible to specify or override options on a per-subnet basis. If clients connected to most of your subnets are expected to get the same values of a given option, you should use global options: you can then override specific values for a small number of subnets. On the other hand, if you use different values in each subnet, it does not make sense to specify global option values (Dhcp4/option-data), rather you should set only subnet-specific values (Dhcp4/subnet[X]/option-data[Y]).

The following commands override the global DNS servers option for a particular subnet, setting a single DNS server with address 192.0.2.3.

"Dhcp4": {
    "subnet4": [
        {
            "option-data": [
                {
                    "name": "domain-name-servers",
                    "code": 6,
                    "space": "dhcp4",
                    "csv-format": true,
                    "data": "192.0.2.3"
                },
                ...
            ],
            ...
        },
        ...
    ],
    ...
}

The currently supported standard DHCPv4 options are listed in Table 7.1, “List of standard DHCPv4 options†and Table 7.2, “List of standard DHCPv4 options (continued)â€. The "Name" and "Code" are the values that should be used as a name in the option-data structures. "Type" designates the format of the data: the meanings of the various types is given in Table 7.3, “List of standard DHCP option typesâ€.

Some options are designated as arrays, which means that more than one value is allowed in such an option. For example the option time-servers allows the specification of more than one IPv4 address, so allowing clients to obtain the addresses of multiple NTP servers.

The Section 7.2.9, “Custom DHCPv4 options†describes the configuration syntax to create custom option definitions (formats). It is generally not allowed to create custom definitions for standard options, even if the definition being created matches the actual option format defined in the RFCs. There is an exception from this rule for standard options for which Kea currently does not provide a definition. In order to use such options, a server administrator must create a definition as described in Section 7.2.9, “Custom DHCPv4 options†in the 'dhcp4' option space. This definition should match the option format described in the relevant RFC but the configuration mechanism will allow any option format as it presently has no means to validate it.

Table 7.1. List of standard DHCPv4 options

NameCodeTypeArray?Returned if not requested?
time-offset2int32falsefalse
routers3ipv4-addresstruetrue
time-servers4ipv4-addresstruefalse
name-servers5ipv4-addresstruefalse
domain-name-servers6ipv4-addresstruetrue
log-servers7ipv4-addresstruefalse
cookie-servers8ipv4-addresstruefalse
lpr-servers9ipv4-addresstruefalse
impress-servers10ipv4-addresstruefalse
resource-location-servers11ipv4-addresstruefalse
boot-size13uint16falsefalse
merit-dump14stringfalsefalse
domain-name15fqdnfalsetrue
swap-server16ipv4-addressfalsefalse
root-path17stringfalsefalse
extensions-path18stringfalsefalse
ip-forwarding19booleanfalsefalse
non-local-source-routing20booleanfalsefalse
policy-filter21ipv4-addresstruefalse
max-dgram-reassembly22uint16falsefalse
default-ip-ttl23uint8falsefalse
path-mtu-aging-timeout24uint32falsefalse
path-mtu-plateau-table25uint16truefalse
interface-mtu26uint16falsefalse
all-subnets-local27booleanfalsefalse
broadcast-address28ipv4-addressfalsefalse
perform-mask-discovery29booleanfalsefalse
mask-supplier30booleanfalsefalse
router-discovery31booleanfalsefalse
router-solicitation-address32ipv4-addressfalsefalse
static-routes33ipv4-addresstruefalse
trailer-encapsulation34booleanfalsefalse
arp-cache-timeout35uint32falsefalse
ieee802-3-encapsulation36booleanfalsefalse
default-tcp-ttl37uint8falsefalse
tcp-keepalive-interval38uint32falsefalse
tcp-keepalive-garbage39booleanfalsefalse


Table 7.2. List of standard DHCPv4 options (continued)

NameCodeTypeArray?Returned if not requested?
nis-domain40stringfalsefalse
nis-servers41ipv4-addresstruefalse
ntp-servers42ipv4-addresstruefalse
vendor-encapsulated-options43emptyfalsefalse
netbios-name-servers44ipv4-addresstruefalse
netbios-dd-server45ipv4-addresstruefalse
netbios-node-type46uint8falsefalse
netbios-scope47stringfalsefalse
font-servers48ipv4-addresstruefalse
x-display-manager49ipv4-addresstruefalse
dhcp-option-overload52uint8falsefalse
dhcp-message56stringfalsefalse
dhcp-max-message-size57uint16falsefalse
vendor-class-identifier60binaryfalsefalse
nwip-domain-name62stringfalsefalse
nwip-suboptions63binaryfalsefalse
nisplus-domain-name64stringfalsefalse
nisplus-servers65ipv4-addresstruefalse
tftp-server-name66stringfalsefalse
boot-file-name67stringfalsefalse
mobile-ip-home-agent68ipv4-addresstruefalse
smtp-server69ipv4-addresstruefalse
pop-server70ipv4-addresstruefalse
nntp-server71ipv4-addresstruefalse
www-server72ipv4-addresstruefalse
finger-server73ipv4-addresstruefalse
irc-server74ipv4-addresstruefalse
streettalk-server75ipv4-addresstruefalse
streettalk-directory-assistance-server76ipv4-addresstruefalse
user-class77binaryfalsefalse
client-system93uint16truefalse
client-ndi94record (uint8, uint8, uint8)falsefalse
uuid-guid97record (uint8, binary)falsefalse
subnet-selection118ipv4-addressfalsefalse
domain-search119binaryfalsefalse
vivco-suboptions124binaryfalsefalse
vivso-suboptions125binaryfalsefalse


Table 7.3. List of standard DHCP option types

NameMeaning
binaryAn arbitrary string of bytes, specified as a set of hexadecimal digits.
booleanBoolean value with allowed values true or false
emptyNo value, data is carried in suboptions
fqdnFully qualified domain name (e.g. www.example.com)
ipv4-addressIPv4 address in the usual dotted-decimal notation (e.g. 192.0.2.1)
ipv6-addressIPv6 address in the usual colon notation (e.g. 2001:db8::1)
recordStructured data that may comprise any types (except "record" and "empty")
stringAny text
uint88 bit unsigned integer with allowed values 0 to 255
uint1616 bit unsigned integer with allowed values 0 to 65535
uint3232 bit unsigned integer with allowed values 0 to 4294967295


7.2.9. Custom DHCPv4 options

Kea supports custom (non-standard) DHCPv4 options. Assume that we want to define a new DHCPv4 option called "foo" which will have a code 222 and will convey a single unsigned 32 bit integer value. We can define such an option by using the following entry in the configuration file:

"Dhcp4": {
    "option-def": [
        {
            "name": "foo",
            "code": 222,
            "type": "uint32",
            "array": false,
            "record-types": "",
            "space": "dhcp4",
            "encapsulate": ""
        }, ...
    ],
    ...
}

The false value of the array parameter determines that the option does NOT comprise an array of "uint32" values but is, instead, a single value. Two other parameters have been left blank: record-types and encapsulate. The former specifies the comma separated list of option data fields if the option comprises a record of data fields. This should be non-empty if the type is set to "record". Otherwise it must be left blank. The latter parameter specifies the name of the option space being encapsulated by the particular option. If the particular option does not encapsulate any option space it should be left blank. Note that the above set of comments define the format of the new option and do not set its values.

The name, code and type parameters are required, all others are optional. The array default value is false. The record-types and encapsulate default values are blank (i.e. ""). The default space is "dhcp4".

Once the new option format is defined, its value is set in the same way as for a standard option. For example the following commands set a global value that applies to all subnets.

"Dhcp4": {
    "option-data": [
        {
            "name": "foo",
            "code": 222,
            "space": "dhcp4",
            "csv-format": true,
            "data": "12345"
        }, ...
    ],
    ...
}

New options can take more complex forms than simple use of primitives (uint8, string, ipv4-address etc): it is possible to define an option comprising a number of existing primitives. Assume we want to define a new option that will consist of an IPv4 address, followed by an unsigned 16 bit integer, followed by a boolean value, followed by a text string. Such an option could be defined in the following way:

"Dhcp4": {
    "option-def": [
        {
            "name": "bar",
            "code": 223,
            "space": "dhcp4",
            "type": "record",
            "array": false,
            "record-types": "ipv4-address, uint16, boolean, string",
            "encapsulate": ""
        }, ...
    ],
    ...
}

The type is set to "record" to indicate that the option contains multiple values of different types. These types are given as a comma-separated list in the record-types field and should be ones from those listed in Table 7.3, “List of standard DHCP option typesâ€.

The values of the option are set as follows:

"Dhcp4": {
    "option-data": [
        {
            "name": "bar",
            "space": "dhcp4",
            "code": 223,
            "csv-format": true,
            "data": "192.0.2.100, 123, true, Hello World"
        }
    ],
    ...
}

csv-format is set to true to indicate that the data field comprises a command-separated list of values. The values in the data must correspond to the types set in the record-types field of the option definition.

Note

In the general case, boolean values are specified as true or false, without quotes. Some specific boolean parameters may accept also "true", "false", 0, 1, "0" and "1". Future versions of Kea will accept all those values for all boolean parameters.

7.2.10. DHCPv4 Vendor Specific Options

Currently there are two option spaces defined for the DHCPv4 daemon: "dhcp4" (for the top level DHCPv4 options) and "vendor-encapsulated-options-space", which is empty by default but in which options can be defined. Such options will be carried in the Vendor Specific Information option (code 43). The following examples show how to define an option "foo" in that space that has a code 1, and comprises an IPv4 address, an unsigned 16 bit integer and a string. The "foo" option is conveyed in a Vendor Specific Information option.

The first step is to define the format of the option:

"Dhcp4": {
    "option-def": [
        {
            "name": "foo",
            "code": 1,
            "space": "vendor-encapsulated-options-space",
            "type": "record",
            "array": false,
            "record-types": "ipv4-address, uint16, string",
            "encapsulate": ""
        }
    ],
    ...
}

(Note that the option space is set to "vendor-encapsulated-options-space".) Once the option format is defined, the next step is to define actual values for that option:

"Dhcp4": {
    "option-data": [
        {
            "name": "foo",
            "space": "vendor-encapsulated-options-space",
            "code": 1,
            "csv-format": true,
            "data": "192.0.2.3, 123, Hello World"
        }
    ],
    ...
}

We also include the Vendor Specific Information option, the option that conveys our sub-option "foo". This is required, else the option will not be included in messages sent to the client.

"Dhcp4": {
    "option-data": [
        {
            "name": "vendor-encapsulated-options"
        }
    ],
    ...
}

Alternatively, the option can be specified using its code.

"Dhcp4": {
    "option-data": [
        {
            "code": 43
        }
    ],
    ...
}

7.2.11. Nested DHCPv4 Options (Custom Option Spaces)

It is sometimes useful to define a completely new option space. This is the case when user creates new option in the standard option space ("dhcp4") and wants this option to convey sub-options. Since they are in a separate space, sub-option codes will have a separate numbering scheme and may overlap with the codes of standard options.

Note that creation of a new option space when defining sub-options for a standard option is not required, because it is created by default if the standard option is meant to convey any sub-options (see Section 7.2.10, “DHCPv4 Vendor Specific Optionsâ€).

Assume that we want to have a DHCPv4 option called "container" with code 222 that conveys two sub-options with codes 1 and 2. First we need to define the new sub-options:

"Dhcp4": {
    "option-def": [
        {
            "name": "subopt1",
            "code": 1,
            "space": "isc",
            "type": "ipv4-address",
            "record-types": "",
            "array": false,
            "encapsulate": ""
        },
        {
            "name": "subopt2",
            "code": 2,
            "space": "isc",
            "type": "string",
            "record-types": "",
            "array": false,
            "encapsulate": ""
        }
    ],
    ...
}

Note that we have defined the options to belong to a new option space (in this case, "isc").

The next step is to define a regular DHCPv4 option with our desired code and specify that it should include options from the new option space:

"Dhcp4": {
    "option-def": [
        ...,
        {
            "name": "container",
            "code": 222,
            "space": "dhcp4",
            "type": "empty",
            "array": false,
            "record-types": "",
            "encapsulate": "isc"
        }
    ],
    ...
}

The name of the option space in which the sub-options are defined is set in the encapsulate field. The type field is set to "empty" to indicate that this option does not carry any data other than sub-options.

Finally, we can set values for the new options:

"Dhcp4": {
    "option-data": [
        {
            "name": "subopt1",
            "code": 1,
            "space": "isc",
            "data": "192.0.2.3"
        },
        }
            "name": "subopt2",
            "code": 2,
            "space": "isc",
            "data": "Hello world"
        },
        {
            "name": "container",
            "code": 222,
            "space": "dhcp4"
        }
    ],
    ...
}

Note that it is possible to create an option which carries some data in addition to the sub-options defined in the encapsulated option space. For example, if the "container" option from the previous example was required to carry an uint16 value as well as the sub-options, the type value would have to be set to "uint16" in the option definition. (Such an option would then have the following data structure: DHCP header, uint16 value, sub-options.) The value specified with the data parameter — which should be a valid integer enclosed in quotes, e.g. "123" — would then be assigned to the uint16 field in the "container" option.

7.2.12. Unspecified Parameters for DHCPv4 Option Configuration

In many cases it is not required to specify all parameters for an option configuration and the default values may be used. However, it is important to understand the implications of not specifying some of them as it may result in configuration errors. The list below explains the behavior of the server when a particular parameter is not explicitly specified:

  • name - the server requires an option name or option code to identify an option. If this parameter is unspecified, the option code must be specified.
  • code - the server requires an option name or option code to identify an option. This parameter may be left unspecified if the name parameter is specified. However, this also requires that the particular option has its definition (it is either a standard option or an administrator created a definition for the option using an 'option-def' structure), as the option definition associates an option with a particular name. It is possible to configure an option for which there is no definition (unspecified option format). Configuration of such options requires the use of option code.
  • space - if the option space is unspecified it will default to 'dhcp4' which is an option space holding DHCPv4 standard options.
  • data - if the option data is unspecified it defaults to an empty value. The empty value is mostly used for the options which have no payload (boolean options), but it is legal to specify empty values for some options which carry variable length data and which the specification allows for the length of 0. For such options, the data parameter may be omitted in the configuration.
  • csv-format - if this value is not specified and the definition for the particular option exists, the server will assume that the option data is specified as a list of comma separated values to be assigned to individual fields of the DHCP option. If the definition does not exist for this option, the server will assume that the data parameter contains the option payload in the binary format (represented as a string of hexadecimal digits). Note that not specifying this parameter doesn't imply that it defaults to a fixed value, but the configuration data interpretation also depends on the presence of the option definition. An administrator must be aware if the definition for the particular option exists when this parameter is not specified. It is generally recommended to not specify this parameter only for the options for which the definition exists, e.g. standard options. Setting csv-format to an explicit value will cause the server to strictly check the format of the option data specified.

7.2.13. Stateless Configuration of DHCPv4 Clients

The DHCPv4 server supports the stateless client configuration whereby the client has an IP address configured (e.g. using manual configuration) and only contacts the server to obtain other configuration parameters, e.g. addresses of DNS servers. In order to obtain the stateless configuration parameters the client sends the DHCPINFORM message to the server with the "ciaddr" set to the address that the client is currently using. The server unicasts the DHCPACK message to the client that includes the stateless configuration ("yiaddr" not set).

The server will respond to the DHCPINFORM when the client is associated with a subnet defined in the server's configuration. An example subnet configuration will look like this:

"Dhcp4": {
    "subnet4": [
        {
            "subnet": "192.0.2.0/24"
            "option-data": [ {
                "name": "domain-name-servers",
                "code": 6,
                "data": "192.0.2.200,192.0.2.201",
                "csv-format": true,
                "space": "dhcp4"
            } ]
        }
    ]
}

This subnet specifies the single option which will be included in the DHCPACK message to the client in response to DHCPINFORM. Note that the subnet definition does not require the address pool configuration if it will be used solely for the stateless configuration.

This server will associate the subnet with the client if one of the following conditions is met:

  • The DHCPINFORM is relayed and the giaddr matches the configured subnet.
  • The DHCPINFORM is unicast from the client and the ciaddr matches the configured subnet.
  • The DHCPINFORM is unicast from the client, the ciaddr is not set but the source address of the IP packet matches the configured subnet.
  • The DHCPINFORM is not relayed and the IP address on the interface on which the message is received matches the configured subnet.

7.2.14. Client Classification in DHCPv4

The DHCPv4 server includes support for client classification. For a deeper discussion of the classification process see Chapter 12, Client Classification.

In certain cases it is useful to differentiate between different types of clients and treat them accordingly. It is envisaged that client classification will be used for changing the behavior of almost any part of the DHCP message processing, including the assignment of leases from different pools, the assignment of different options (or different values of the same options) etc. In the current release of the software however, there are only three mechanisms that take advantage of client classification: subnet selection, assignment of different options, and, for cable modems, there are specific options for use with the TFTP server address and the boot file field.

Kea can be instructed to limit access to given subnets based on class information. This is particularly useful for cases where two types of devices share the same link and are expected to be served from two different subnets. The primary use case for such a scenario is cable networks. Here, there are two classes of devices: the cable modem itself, which should be handed a lease from subnet A and all other devices behind the modem that should get a lease from subnet B. That segregation is essential to prevent overly curious users from playing with their cable modems. For details on how to set up class restrictions on subnets, see Section 12.6, “Configuring Subnets With Class Informationâ€.

The process of doing classification is conducted in three steps. The first step is to assess an incoming packet and assign it to zero or more classes. The second step is to choose a subnet, possibly based on the class information. The third step is to assign options, again possibly based on the class information.

There are two methods of doing classification. The first is automatic and relies on examining the values in the vendor class options. Information from these options is extracted and a class name is constructed from it and added to the class list for the packet. The second allows you to specify an expression that is evaluated for each packet. If the result is true the packet is a member of the class.

Note

Care should be taken with client classification as it is easy for clients that do not meet class criteria to be denied any service altogether.

7.2.14.1. Setting Fixed Fields in Classification

It is possible to specify that clients belonging to a particular class should receive packets with specific values in certain fixed fields. In particular, three fixed fields are supported: next-server (that conveys an IPv4 address, which is set in the siaddr field), server-hostname (that conveys a server hostname, can be up to 64 bytes long and will be sent in the sname field) and boot-file-name (that conveys the configuration file, can be up to 128 bytes long and will be sent using file field).

Obviously, there are many ways to assign clients to specific classes, but for the PXE clients the client architecture type option (code 93) seems to be particularly suited to make the distinction. The following example checks if the client identifies itself as PXE device with architecture EFI x86-64, and sets several fields if it does. See Section 2.1 of RFC 4578) or the documentation of your client for specific values.

"Dhcp4": {
    "client-classes": [
        {
            "name": "ipxe_efi_x64",
            "test": "option[93].hex == 0x0009",
            "next-server": "192.0.2.254",
            "server-hostname": "hal9000",
            "boot-file-name": "/dev/null"
        },
        ...
    ],
    ...
          }

If there are multiple classes defined and an incoming packet is matched to multiple classes, the class whose name is alphabetically the first is used.

7.2.14.2. Using Vendor Class Information in Classification

The server checks whether an incoming packet includes the vendor class identifier option (60). If it does, the content of that option is prepended with "VENDOR_CLASS_", it is interpreted as a class. For example, modern cable modems will send this option with value "docsis3.0" and as a result the packet will belong to class "VENDOR_CLASS_docsis3.0".

Note

Kea 1.0 and earlier versions performed special actions for clients that were in VENDOR_CLASS_docsis3.0. This is no longer the case in Kea 1.1 and later. In these versions the old behavior can be achieved by defining VENDOR_CLASS_docsis3.0 and setting its next-server and boot-file-name values appropriately.

This example shows a configuration using an automatically generated "VENDOR_CLASS_" class. The administrator of the network has decided that addresses from range 192.0.2.10 to 192.0.2.20 are going to be managed by the Dhcp4 server and only clients belonging to the docsis3.0 client class are allowed to use that pool.

"Dhcp4": {
    "subnet4": [
        {
            "subnet": "192.0.2.0/24",
            "pools": [ { "pool": "192.0.2.10 - 192.0.2.20" } ],
            "client-class": "VENDOR_CLASS_docsis3.0"
        }
    ],
    ...
}

7.2.14.3. Defining and Using Custom Classes

The following example shows how to configure a class using an expression and a subnet that makes use of the class. This configuration defines the class named "Client_foo". It is comprised of all clients who's client ids (option 61) start with the string "foo". Members of this class will be given addresses from 192.0.2.10 to 192.0.2.20 and the addresses of their DNS servers set to 192.0.2.1 and 192.0.2.2.

"Dhcp4": {
    "client-classes": [
        {
            "name": "Client_foo",
            "test": "substring(option[61].hex,0,3) == 'foo'",
            "option-data": [
                {
                    "name": "domain-name-servers",
                    "code": 6,
                    "space": "dhcp4",
                    "csv-format": true,
                    "data": "192.0.2.1, 192.0.2.2"
                }
            ]
        },
        ...
    ],
    "subnet4": [
        {
            "subnet": "192.0.2.0/24",
            "pools": [ { "pool": "192.0.2.10 - 192.0.2.20" } ],
            "client-class": "Client_foo"
        },
        ...
    ],
    ...
}

7.2.15. DDNS for DHCPv4

As mentioned earlier, kea-dhcp4 can be configured to generate requests to the DHCP-DDNS server (referred to here as "D2" ) to update DNS entries. These requests are known as NameChangeRequests or NCRs. Each NCR contains the following information:

  1. Whether it is a request to add (update) or remove DNS entries

  2. Whether the change requests forward DNS updates (A records), reverse DNS updates (PTR records), or both.

  3. The FQDN, lease address, and DHCID

The parameters for controlling the generation of NCRs for submission to D2 are contained in the dhcp-ddns section of the kea-dhcp4 server configuration. The mandatory parameters for the DHCP DDNS configuration are enable-updates which is unconditionally required, and qualifying-suffix which has no default value and is required when enable-updates is set to true. The two (disabled and enabled) minimal DHCP DDNS configurations are:

"Dhcp4": {
    "dhcp-ddns": {
        "enable-updates": false
    },
    ...
}

and for example:

"Dhcp4": {
    "dhcp-ddns": {
        "enable-updates": true,
        "qualifying-suffix": "example."
    },
    ...
}

The default values for the "dhcp-ddns" section are as follows:

  • "server-ip": "127.0.0.1"
  • "server-port": 53001
  • "sender-ip": ""
  • "sender-port": 0
  • "max-queue-size": 1024
  • "ncr-protocol": "UDP"
  • "ncr-format": "JSON"
  • "override-no-update": false
  • "override-client-update": false
  • "replace-client-name": "never"
  • "generated-prefix": "myhost"

7.2.15.1. DHCP-DDNS Server Connectivity

In order for NCRs to reach the D2 server, kea-dhcp4 must be able to communicate with it. kea-dhcp4 uses the following configuration parameters to control this communication:

  • enable-updates - determines whether or not kea-dhcp4 will generate NCRs. By default, this value is false hence DDNS updates are disabled. To enable DDNS updates set this value to true:
  • server-ip - IP address on which D2 listens for requests. The default is the local loopback interface at address 127.0.0.1. You may specify either an IPv4 or IPv6 address.
  • server-port - port on which D2 listens for requests. The default value is 53001.
  • sender-ip - IP address which kea-dhcp4 should use to send requests to D2. The default value is blank which instructs kea-dhcp4 to select a suitable address.
  • sender-port - port which kea-dhcp4 should use to send requests to D2. The default value of 0 instructs kea-dhcp4 to select a suitable port.
  • max-queue-size - maximum number of requests allowed to queue waiting to be sent to D2. This value guards against requests accumulating uncontrollably if they are being generated faster than they can be delivered. If the number of requests queued for transmission reaches this value, DDNS updating will be turned off until the queue backlog has been sufficiently reduced. The intention is to allow the kea-dhcp4 server to continue lease operations without running the risk that its memory usage grows without limit. The default value is 1024.
  • ncr-protocol - socket protocol use when sending requests to D2. Currently only UDP is supported. TCP may be available in an upcoming release.
  • ncr-format - packet format to use when sending requests to D2. Currently only JSON format is supported. Other formats may be available in future releases.

By default, kea-dhcp-ddns is assumed to be running on the same machine as kea-dhcp4, and all of the default values mentioned above should be sufficient. If, however, D2 has been configured to listen on a different address or port, these values must be altered accordingly. For example, if D2 has been configured to listen on 192.168.1.10 port 900, the following configuration would be required:

"Dhcp4": {
    "dhcp-ddns": {
        "server-ip": "192.168.1.10",
        "server-port": 900,
        ...
    },
    ...
}

7.2.15.2. When Does the kea-dhcp4 Server Generate DDNS Requests?

kea-dhcp4 follows the behavior prescribed for DHCP servers in RFC 4702. It is important to keep in mind that kea-dhcp4 provides the initial decision making of when and what to update and forwards that information to D2 in the form of NCRs. Carrying out the actual DNS updates and dealing with such things as conflict resolution are within the purview of D2 itself (Chapter 10, The DHCP-DDNS Server). This section describes when kea-dhcp4 will generate NCRs and the configuration parameters that can be used to influence this decision. It assumes that the enable-updates parameter is true.

In general, kea-dhcp4 will generate DDNS update requests when:

  1. A new lease is granted in response to a DHCP REQUEST

  2. An existing lease is renewed but the FQDN associated with it has changed.

  3. An existing lease is released in response to a DHCP RELEASE

In the second case, lease renewal, two DDNS requests will be issued: one request to remove entries for the previous FQDN and a second request to add entries for the new FQDN. In the last case, a lease release, a single DDNS request to remove its entries will be made.

The decision making involved when granting a new lease (the first case) is more involved. When a new lease is granted, kea-dhcp4 will generate a DDNS update request if the DHCP REQUEST contains either the FQDN option (code 81) or the Host Name option (code 12). If both are present, the server will use the FQDN option. By default kea-dhcp4 will respect the FQDN N and S flags specified by the client as shown in the following table:

Table 7.4. Default FQDN Flag Behavior

Client Flags:N-SClient IntentServer ResponseServer Flags:N-S-O
0-0 Client wants to do forward updates, server should do reverse updates Server generates reverse-only request1-0-0
0-1Server should do both forward and reverse updatesServer generates request to update both directions0-1-0
1-0Client wants no updates doneServer does not generate a request1-0-0

The first row in the table above represents "client delegation". Here the DHCP client states that it intends to do the forward DNS updates and the server should do the reverse updates. By default, kea-dhcp4 will honor the client's wishes and generate a DDNS request to the D2 server to update only reverse DNS data. The parameter override-client-update can be used to instruct the server to override client delegation requests. When this parameter is true, kea-dhcp4 will disregard requests for client delegation and generate a DDNS request to update both forward and reverse DNS data. In this case, the N-S-O flags in the server's response to the client will be 0-1-1 respectively.

(Note that the flag combination N=1, S=1 is prohibited according to RFC 4702. If such a combination is received from the client, the packet will be dropped by kea-dhcp4.)

To override client delegation, set the following values in the configuration file:

"Dhcp4": {
    "dhcp-ddns": {
        "override-client-update": true,
        ...
    },
    ...
}

The third row in the table above describes the case in which the client requests that no DNS updates be done. The parameter, override-no-update, can be used to instruct the server to disregard the client's wishes. When this parameter is true, kea-dhcp4 will generate DDNS update requests to kea-dhcp-ddns even if the client requests that no updates be done. The N-S-O flags in the server's response to the client will be 0-1-1.

To override client delegation, the following values should be set in your configuration:

"Dhcp4": {
    "dhcp-ddns": {
        "override-no-update": true,
        ...
    },
    ...
}

kea-dhcp4 will always generate DDNS update requests if the client request only contains the Host Name option. In addition it will include an FQDN option in the response to the client with the FQDN N-S-O flags set to 0-1-0 respectively. The domain name portion of the FQDN option will be the name submitted to D2 in the DDNS update request.

7.2.15.3. kea-dhcp4 name generation for DDNS update requests

Each NameChangeRequest must of course include the fully qualified domain name whose DNS entries are to be affected. kea-dhcp4 can be configured to supply a portion or all of that name based upon what it receives from the client in the DHCP REQUEST.

The default rules for constructing the FQDN that will be used for DNS entries are:

  1. If the DHCPREQUEST contains the client FQDN option, the candidate name is taken from there, otherwise it is taken from the Host Name option.

  2. If the candidate name is a partial (i.e. unqualified) name then add a configurable suffix to the name and use the result as the FQDN.

  3. If the candidate name provided is empty, generate a FQDN using a configurable prefix and suffix.

  4. If the client provided neither option, then no DNS action will be taken.

These rules can amended by setting the replace-client-name parameter which provides the following modes of behavior:

  • never - Use the name the client sent. If the client sent no name, do not generate one. This is the default mode.

  • always - Replace the name the client sent. If the client sent no name, generate one for the client.

  • when-present - Replace the name the client sent. If the client sent no name, do not generate one.

  • when-not-present - Use the name the client sent. If the client sent no name, generate one for the client.

Note

Note that formerly, this parameter was a boolean and permitted only values of true and false. Boolean values will still be accepted but may eventually be deprecated. A value of true equates to when-present, false equates to never.

For example, To instruct kea-dhcp4 to always generate the FQDN for a client, set the parameter replace-client-name to always as follows:

"Dhcp4": {
    "dhcp-ddns": {
        "replace-client-name": "always",
        ...
    },
    ...
}

The prefix used in the generation of a FQDN is specified by the generated-prefix parameter. The default value is "myhost". To alter its value, simply set it to the desired string:

"Dhcp4": {
    "dhcp-ddns": {
        "generated-prefix": "another.host",
        ...
    },
    ...
}

The suffix used when generating a FQDN or when qualifying a partial name is specified by the qualifying-suffix parameter. This parameter has no default value, thus it is mandatory when DDNS updates are enabled. To set its value simply set it to the desired string:

"Dhcp4": {
    "dhcp-ddns": {
        "qualifying-suffix": "foo.example.org",
        ...
    },
    ...
}

When generating a name, kea-dhcp4 will construct name of the format:

[generated-prefix]-[address-text].[qualifying-suffix].

where address-text is simply the lease IP address converted to a hyphenated string. For example, if the lease address is 172.16.1.10, the qualifying suffix "example.com", and the default value is used for generated-prefix, the generated FQDN would be:

myhost-172-16-1-10.example.com.

7.2.16. Next Server (siaddr)

In some cases, clients want to obtain configuration from a TFTP server. Although there is a dedicated option for it, some devices may use the siaddr field in the DHCPv4 packet for that purpose. That specific field can be configured using next-server directive. It is possible to define it in the global scope or for a given subnet only. If both are defined, the subnet value takes precedence. The value in subnet can be set to 0.0.0.0, which means that next-server should not be sent. It may also be set to an empty string, which means the same as if it was not defined at all, i.e. use the global value.

"Dhcp4": {
    "next-server": "192.0.2.123",
    ...,
    "subnet4": [
        {
            "next-server": "192.0.2.234",
            ...
        }
    ]
}

7.2.17. Echoing Client-ID (RFC 6842)

The original DHCPv4 specification (RFC 2131) states that the DHCPv4 server must not send back client-id options when responding to clients. However, in some cases that confused clients that did not have MAC address or client-id; see RFC 6842. for details. That behavior has changed with the publication of RFC 6842 which updated RFC 2131. That update states that the server must send client-id if the client sent it. That is Kea's default behavior. However, in some cases older devices that do not support RFC 6842. may refuse to accept responses that include the client-id option. To enable backward compatibility, an optional configuration parameter has been introduced. To configure it, use the following configuration statement:

"Dhcp4": {
    "echo-client-id": false,
    ...
}

7.2.18. Using Client Identifier and Hardware Address

The DHCP server must be able to identify the client (and distinguish it from other clients) from which it receives the message. There are many reasons why this identification is required and the most important ones are:

  • When the client contacts the server to allocate a new lease, the server must store the client identification information in the lease database as a search key.
  • When the client is trying to renew or release the existing lease, the server must be able to find the existing lease entry in the database for this client, using the client identification information as a search key.
  • Some configurations use static reservations for the IP addresses and other configuration information. The server's administrator uses client identification information to create these static assignments.
  • In the dual stack networks there is often a need to correlate the lease information stored in DHCPv4 and DHCPv6 server for a particular host. Using common identification information by the DHCPv4 and DHCPv6 client allows the network administrator to achieve this correlation and better administer the network.

DHCPv4 makes use of two distinct identifiers which are placed by the client in the queries sent to the server and copied by the server to its responses to the client: "chaddr" and "client identifier". The former was introduced as a part of the BOOTP specification and it is also used by DHCP to carry the hardware address of the interface used to send the query to the server (MAC address for the Ethernet). The latter is carried in the Client-identifier option, introduced in RFC 2132.

RFC 2131 indicates that the server may use both of these identifiers to identify the client but the "client identifier", if present, takes precedence over "chaddr". One of the reasons for this is that "client identifier" is independent from the hardware used by the client to communicate with the server. For example, if the client obtained the lease using one network card and then the network card is moved to another host, the server will wrongly identify this host is the one which has obtained the lease. Moreover, RFC 4361 gives the recommendation to use a DUID (see RFC 3315, the DHCPv6 specification) carried as "client identifier" when dual stack networks are in use to provide consistent identification information of the client, regardless of the protocol type it is using. Kea adheres to these specifications and the "client identifier" by default takes precedence over the value carried in "chaddr" field when the server searches, creates, updates or removes the client's lease.

When the server receives a DHCPDISCOVER or DHCPREQUEST message from the client, it will try to find out if the client already has a lease in the database and will hand out that lease rather than allocate a new one. Each lease in the lease database is associated with the "client identifier" and/or "chaddr". The server will first use the "client identifier" (if present) to search the lease. If the lease is found, the server will treat this lease as belonging to the client even if the current "chaddr" and the "chaddr" associated with the lease do not match. This facilitates the scenario when the network card on the client system has been replaced and thus the new MAC address appears in the messages sent by the DHCP client. If the server fails to find the lease using the "client identifier" it will perform another lookup using the "chaddr". If this lookup returns no result, the client is considered as not having a lease and the new lease will be created.

A common problem reported by network operators is that poor client implementations do not use stable client identifiers, instead generating a new "client identifier" each time the client connects to the network. Another well known case is when the client changes its "client identifier" during the multi-stage boot process (PXE). In such cases, the MAC address of the client's interface remains stable and using "chaddr" field to identify the client guarantees that the particular system is considered to be the same client, even though its "client identifier" changes.

To address this problem, Kea includes a configuration option which enables client identification using "chaddr" only by instructing the server to disregard server to "ignore" the "client identifier" during lease lookups and allocations for a particular subnet. Consider the following simplified server configuration:

"Dhcp4": {
    ...
    "match-client-id": true,
    ...
    "subnet4": [
    {
        "subnet": "192.0.10.0/24",
        "pools": [ { "pool": "192.0.2.23-192.0.2.87" } ],
        "match-client-id": false
    },
    {
        "subnet": "10.0.0.0/8",
        "pools": [ { "pool": "10.0.0.23-10.0.2.99" } ],
    }
    ]
}

The match-client-id is a boolean value which controls this behavior. The default value of true indicates that the server will use the "client identifier" for lease lookups and "chaddr" if the first lookup returns no results. The false means that the server will only use the "chaddr" to search for client"s lease. Whether the DHCID for DNS updates is generated from the "client identifier" or "chaddr" is controlled through the same parameter accordingly.

The match-client-id parameter may appear both in the global configuration scope and/or under any subnet declaration. In the example shown above, the effective value of the match-client-id will be false for the subnet 192.0.10.0/24, because the subnet specific setting of the parameter overrides the global value of the parameter. The effective value of the match-client-id for the subnet 10.0.0.0/8 will be set to true because the subnet declaration lacks this parameter and the global setting is by default used for this subnet. In fact, the global entry for this parameter could be omitted in this case, because true is the default value.

It is important to explain what happens when the client obtains its lease for one setting of the match-client-id and then renews when the setting has been changed. First consider the case when the client obtains the lease when the match-client-id is set to true. The server will store the lease information including "client identifier" (if supplied) and "chaddr" in the lease database. When the setting is changed and the client renews the lease the server will determine that it should use the "chaddr" to search for the existing lease. If the client hasn't changed its MAC address the server should successfully find the existing lease. The "client identifier" associated with the returned lease is ignored and the client is allowed to use this lease. When the lease is renewed only the "chaddr" is recorded for this lease according to the new server setting.

In the second case the client has the lease with only a "chaddr" value recorded. When the setting is changed to match-client-id set to true the server will first try to use the "client identifier" to find the existing client's lease. This will return no results because the "client identifier" was not recorded for this lease. The server will then use the "chaddr" and the lease will be found. If the lease appears to have no "client identifier" recorded, the server will assume that this lease belongs to the client and that it was created with the previous setting of the match-client-id. However, if the lease contains "client identifier" which is different from the "client identifier" used by the client the lease will be assumed to belong to another client and the new lease will be allocated.

7.2.19. DHCPv4-over-DHCPv6: DHCPv4 Side

The support of DHCPv4-over-DHCPv6 transport is described in RFC 7341 and is implemented using cooperating DHCPv4 and DHCPv6 servers. This section is about the configuration of the DHCPv4 side (the DHCPv6 side is described in Section 8.2.20, “DHCPv4-over-DHCPv6: DHCPv6 Sideâ€).

Note

DHCPv4-over-DHCPv6 support is experimental and the details of the inter-process communication can change: both the DHCPv4 and DHCPv6 sides should be running the same version of Kea.

The dhcp4o6-port global parameter specifies the first of the two consecutive ports of the UDP sockets used for the communication between the DHCPv6 and DHCPv4 servers (the DHCPv4 server is bound to ::1 on port + 1 and connected to ::1 on port).

With DHCPv4-over-DHCPv6 the DHCPv4 server does not have access to several of the identifiers it would normally use to select a subnet. In order to address this issue three new configuration entires have been added. The presence of any of these allows the subnet to be used with DHCPv4-over-DHCPv6. These entries are:

  • 4o6-subnet: Takes a prefix (i.e., an IPv6 address followed by a slash and a prefix length) which is matched against the source address.
  • 4o6-interface-id: Takes a relay interface ID option value.
  • 4o6-interface: Takes an interface name which is matched against the incoming interface name.

The following configuration was used during some tests:

{

# DHCPv4 conf
"Dhcp4": {
    "interfaces-config": {
        "interfaces": [ "eno33554984" ]
    },

    "lease-database": {
        "type": "memfile",
        "name": "leases4"
    },

    "valid-lifetime": 4000,

    "subnet4": [ {
        "subnet": "10.10.10.0/24",
        "4o6-interface": "eno33554984",
        "4o6-subnet": "2001:db8:1:1::/64",
        "pools": [ { "pool": "10.10.10.100 - 10.10.10.199" } ]
    } ],

    "dhcp4o6-port": 6767

},

"Logging": {
    "loggers": [ {
        "name": "kea-dhcp4",
        "output_options": [ {
            "output": "/tmp/kea-dhcp4.log"
        } ],
        "severity": "DEBUG",
        "debuglevel": 0
    } ]
}

}

7.3. Host Reservation in DHCPv4

There are many cases where it is useful to provide a configuration on a per host basis. The most obvious one is to reserve a specific, static address for exclusive use by a given client (host) †the returning client will receive the same address from the server every time, and other clients will generally not receive that address. Another example when the host reservations are applicable is when a host has specific requirements, e.g. a printer that needs additional DHCP options. Yet another possible use case is to define unique names for hosts.

Note that there may be cases when the new reservation has been made for the client for the address being currently in use by another client. We call this situation a "conflict". The conflicts get resolved automatically over time as described in subsequent sections. Once the conflict is resolved, the client will keep receiving the reserved configuration when it renews.

Host reservations are defined as parameters for each subnet. Each host has to be identified by an identifier, for example the hardware/MAC address. There is an optional reservations array in the Subnet4 element. Each element in that array is a structure that holds information about reservations for a single host. In particular, the structure has to have an identifier that uniquely identifies a host. In the DHCPv4 context, the identifier is usually a hardware or MAC address. In most cases an IP address will be specified. It is also possible to specify a hostname, host specific options or fields carried within DHCPv4 message such as siaddr, sname or file.

In Kea 1.0.0 it was only possible to create host reservations using client's hardware address. Host reservations by client identifier, DUID and circuit-id have been added in Kea 1.1.0.

The following example shows how to reserve addresses for specific hosts:

"subnet4": [
    {
        "pools": [ { "pool":  "192.0.2.1 - 192.0.2.200" } ],
        "subnet": "192.0.2.0/24",
        "interface": "eth0",
        "reservations": [
            {
                "hw-address": "1a:1b:1c:1d:1e:1f",
                "ip-address": "192.0.2.202"
            },
            {
                "duid": "0a:0b:0c:0d:0e:0f",
                "ip-address": "192.0.2.100",
                "hostname": "alice-laptop"
            },
            {
                "circuit-id": "'charter950'",
                "ip-address": "192.0.2.203"
            },
            {
                "client-id": "01:11:22:33:44:55:66",
                "ip-address": "192.0.2.204"
            }
        ]
    }
]

The first entry reserves the 192.0.2.202 address for the client that uses a MAC address of 1a:1b:1c:1d:1e:1f. The second entry reserves the address 192.0.2.100 and the hostname of alice-laptop for the client using a DUID 0a:0b:0c:0d:0e:0f. (Note that if you plan to do DNS updates, it is strongly recommended for the hostnames to be unique.) The third example reserves address 192.0.3.203 to a client whose request would be relayed by a relay agent that inserts a circuid-it option with the value 'charter950'. The fourth entry reserves address 192.0.2.204 for a client that uses a client identifier with value 01:11:22:33:44:55:66.

The above example is used for ilustrational purposes only and in actual deployments it is recommended to use as few types as possible (preferably just one). See Section 7.3.9, “Fine Tuning DHCPv4 Host Reservation†for a detailed discussion of this point.

Making a reservation for a mobile host that may visit multiple subnets requires a separate host definition in each subnet it is expected to visit. It is not allowed to define multiple host definitions with the same hardware address in a single subnet. Multiple host definitions with the same hardware address are valid if each is in a different subnet.

Adding host reservation incurs a performance penalty. In principle, when a server that does not support host reservation responds to a query, it needs to check whether there is a lease for a given address being considered for allocation or renewal. The server that also supports host reservation has to perform additional checks: not only if the address is currently used (i.e. if there is a lease for it), but also whether the address could be used by someone else (i.e. there is a reservation for it). That additional check incurs additional overhead.

7.3.1. Address Reservation Types

In a typical scenario there is an IPv4 subnet defined, e.g. 192.0.2.0/24, with certain part of it dedicated for dynamic allocation by the DHCPv4 server. That dynamic part is referred to as a dynamic pool or simply a pool. In principle, a host reservation can reserve any address that belongs to the subnet. The reservations that specify addresses that belong to configured pools are called "in-pool reservations". In contrast, those that do not belong to dynamic pools are called "out-of-pool reservations". There is no formal difference in the reservation syntax and both reservation types are handled uniformly. However, upcoming releases may offer improved performance if there are only out-of-pool reservations as the server will be able to skip reservation checks when dealing with existing leases. Therefore, system administrators are encouraged to use out-of-pool reservations if possible.

7.3.2. Conflicts in DHCPv4 Reservations

As the reservations and lease information are stored separately, conflicts may arise. Consider the following series of events. The server has configured the dynamic pool of addresses from the range of 192.0.2.10 to 192.0.2.20. Host A requests an address and gets 192.0.2.10. Now the system administrator decides to reserve address 192.0.2.10 for Host B. In general, reserving an address that is currently assigned to someone else is not recommended, but there are valid use cases where such an operation is warranted.

The server now has a conflict to resolve. Let's analyze the situation here. If Host B boots up and requests an address, the server is not able to assign the reserved address 192.0.2.10. A naive approach would to be immediately remove the existing lease for the Host A and create a new one for the Host B. That would not solve the problem, though, because as soon as the Host B gets the address, it will detect that the address is already in use by the Host A and would send the DHCPDECLINE message. Therefore, in this situation, the server has to temporarily assign a different address (not matching what has been reserved) to the Host B.

When Host A renews its address, the server will discover that the address being renewed is now reserved for another host - Host B. Therefore the server will inform the Host A that it is no longer allowed to use it by sending a DHCPNAK message. The server will not remove the lease, though, as there's small chance that the DHCPNAK may be lost if the network is lossy. If that happens, the client will not receive any responses, so it will retransmit its DHCPREQUEST packet. Once the DHCPNAK is received by Host A, it will revert to the server discovery and will eventually get a different address. Besides allocating a new lease, the server will also remove the old one. As a result, address 192.0.2.10 will become free . When Host B tries to renew its temporarily assigned address, the server will detect that it has a valid lease, but there is a reservation for a different address. The server will send DHCPNAK to inform Host B that its address is no longer usable, but will keep its lease (again, the DHCPNAK may be lost, so the server will keep it, until the client returns for a new address). Host B will revert to the server discovery phase and will eventually send a DHCPREQUEST message. This time the server will find out that there is a reservation for that host and the reserved address 192.0.2.10 is not used, so it will be granted. It will also remove the lease for the temporarily assigned address that Host B previously obtained.

This recovery will succeed, even if other hosts will attempt to get the reserved address. Had the Host C requested address 192.0.2.10 after the reservation was made, the server will either offer a different address (when responding to DHCPDISCOVER) or would send DHCPNAK (when responding to DHCPREQUEST).

This recovery mechanism allows the server to fully recover from a case where reservations conflict with the existing leases. This procedure takes time and will roughly take as long as the value set for of renew-timer. The best way to avoid such recovery is to not define new reservations that conflict with existing leases. Another recommendation is to use out-of-pool reservations. If the reserved address does not belong to a pool, there is no way that other clients could get this address.

7.3.3. Reserving a Hostname

When the reservation for a client includes the hostname, the server will return this hostname to the client in the Client FQDN or Hostname options. The server responds with the Client FQDN option only if the client has included Client FQDN option in its message to the server. The server will respond with the Hostname option if the client included Hostname option in its message to the server or when the client requested Hostname option using Parameter Request List option. The server will return the Hostname option even if it is not configured to perform DNS updates. The reserved hostname always takes precedence over the hostname supplied by the client or the autogenerated (from the IPv4 address) hostname.

The server qualifies the reserved hostname with the value of the qualifying-suffix parameter. For example, the following subnet configuration:

    {
        "subnet4": [ {
            "subnet": "10.0.0.0/24",
            "pools": [ { "pool": "10.0.0.10-10.0.0.100" } ],
            "reservations": [
               {
                 "hw-address": "aa:bb:cc:dd:ee:ff",
                 "hostname": "alice-laptop"
               }
            ]
         }],
        "dhcp-ddns": {
            "enable-updates": true,
            "qualifying-suffix": "example.isc.org."
        }
    }

will result in assigning the "alice-laptop.example.isc.org." hostname to the client using the MAC address "aa:bb:cc:dd:ee:ff". If the qualifying-suffix is not specified, the default (empty) value will be used, and in this case the value specified as a hostname will be treated as fully qualified name. Thus, by leaving the qualifying-suffix empty it is possible to qualify hostnames for the different clients with different domain names:

    {
        "subnet4": [ {
            "subnet": "10.0.0.0/24",
            "pools": [ { "pool": "10.0.0.10-10.0.0.100" } ],
            "reservations": [
               {
                 "hw-address": "aa:bb:cc:dd:ee:ff",
                 "hostname": "alice-laptop.isc.org."
               },
               {
                 "hw-address": "12:34:56:78:99:AA",
                 "hostname": "mark-desktop.example.org."
               }

            ]
         }],
        "dhcp-ddns": {
            "enable-updates": true,
        }
    }

7.3.4. Including Specific DHCPv4 Options in Reservations

Kea 1.1.0 introduced the ability to specify options on a per host basis. The options follow the same rules as any other options. These can be standard options (see Section 7.2.8, “Standard DHCPv4 Optionsâ€), custom options (see Section 7.2.9, “Custom DHCPv4 optionsâ€) or vendor specific options (see Section 7.2.10, “DHCPv4 Vendor Specific Optionsâ€). The following example demonstrates how standard options can be defined.

{
    "subnet4": [ {
        "reservations": [
        {
            "hw-address": "aa:bb:cc:dd:ee:ff",
            "ip-address": "192.0.2.1",
            "option-data": [
            {
                "name": "cookie-servers",
                "data": "10.1.1.202,10.1.1.203"
            },
            {
                "name": "log-servers",
                "data": "10.1.1.200,10.1.1.201"
            } ]
        } ]
    } ]
}

Vendor specific options can be reserved in a similar manner:

{
    "subnet4": [ {
        "reservations": [
        {
            "hw-address": "aa:bb:cc:dd:ee:ff",
            "ip-address": "10.0.0.7",
            "option-data": [
            {
                "name": "vivso-suboptions",
                "data": "4491"
            },
            {
                "name": "tftp-servers",
                "space": "vendor-4491",
                "data": "10.1.1.202,10.1.1.203"
            } ]
        } ]
    } ]
}

Options defined on host level have the highest priority. In other words, if there are options defined with the same type on global, subnet, class and host level, the host specific values will be used.

7.3.5. Reserving Next Server, Server Hostname and Boot File Name

BOOTP/DHCPv4 messages include "siaddr", "sname" and "file" fields. Even though, DHCPv4 includes corresponding options, such as option 66 and option 67, some clients may not support these options. For this reason, server administrators often use the "siaddr", "sname" and "file" fields instead.

With Kea, it is possible to make static reservations for these DHCPv4 message fields:

{
    "subnet4": [ {
        "reservations": [
        {
            "hw-address": "aa:bb:cc:dd:ee:ff",
            "next-server": "10.1.1.2",
            "server-hostname": "server-hostname.example.org",
            "boot-file-name": "/tmp/bootfile.efi"
        } ]
    } ]
}

Note that those parameters can be specified in combination with other parameters for a reservation, e.g. reserved IPv4 address. These parameters are optional, i.e. a subset of them can specified, or all of them can be omitted.

7.3.6. Reserving Client Classes in DHCPv4

Section 12.4, “Using Expressions In Classification†explains how to configure the server to assign classes to a client based on the content of the options that this client sends to the server. Host reservations mechanisms also allow for statically assigning classes to the clients. The definitions of these classes must exist in the Kea configuration. The following configuration snippet shows how to specify that a client belongs to classes reserved-class1 and reserved-class2. Those classes are associated with specific options being sent to the clients which belong to them.

{
    "client-classes": [
    {
       "name": "reserved-class1",
       "option-data": [
       {
           "name": "routers",
           "data": "10.0.0.200"
       }
       ]
    },
    {
       "name": "reserved-class2",
       "option-data": [
       {
           "name": "domain-name-servers",
           "data": "10.0.0.201"
       }
       ]
    }
    ],
    "subnet4": [ {
        "subnet": "10.0.0.0/24",
        "pools": [ { "pool": "10.0.0.10-10.0.0.100" } ],
        "reservations": [
        {
            "hw-address": "aa:bb:cc:dd:ee:ff",
            
            "client-classes": [ "reserved-class1", "reserved-class2" ]
            
        }
        ]
    } ]
}

Static class assignments, as shown above, can be used in conjuction with classification using expressions.

7.3.7. Storing Host Reservations in MySQL or PostgreSQL

It is possible to store host reservations in MySQL or PostgreSQL database. See Section 7.2.3, “Hosts Storage†for information on how to configure Kea to use reservations stored in MySQL or PostgreSQL. Kea does not provide any dedicated tools for managing reservations in a database. The Kea wiki http://kea.isc.org/wiki/HostReservationsHowTo provides detailed information and examples of how reservations can be inserted into the database.

Note

In Kea 1.1.0 maximum length of an option specified per host is arbitrarily set to 4096 bytes.

7.3.8. Storing host reservations in CQL (Cassandra)

Kea currently does not support storing reservations in Cassandra (CQL).

7.3.9. Fine Tuning DHCPv4 Host Reservation

The host reservation capability introduces additional restrictions for the allocation engine (the component of Kea that selects an address for a client) during lease selection and renewal. In particular, three major checks are necessary. First, when selecting a new lease, it is not sufficient for a candidate lease to not be used by another DHCP client. It also must not be reserved for another client. Second, when renewing a lease, additional check must be performed whether the address being renewed is not reserved for another client. Finally, when a host renews an address, the server has to check whether there is a reservation for this host, so the existing (dynamically allocated) address should be revoked and the reserved one be used instead.

Some of those checks may be unnecessary in certain deployments and not performing them may improve performance. The Kea server provides the reservation-mode configuration parameter to select the types of reservations allowed for the particular subnet. Each reservation type has different constraints for the checks to be performed by the server when allocating or renewing a lease for the client. Allowed values are:

  • all - enables all host reservation types. This is the default value. This setting is the safest and the most flexible. It allows in-pool and out-of-pool reservations. As all checks are conducted, it is also the slowest.
  • out-of-pool - allows only out of pool host reservations. With this setting in place, the server may assume that all host reservations are for addresses that do not belong to the dynamic pool. Therefore it can skip the reservation checks when dealing with in-pool addresses, thus improving performance. Do not use this mode if any of your reservations use in-pool address. Caution is advised when using this setting: Kea 1.1.0 does not sanity check the reservations against reservation-mode and misconfiguration may cause problems.
  • disabled - host reservation support is disabled. As there are no reservations, the server will skip all checks. Any reservations defined will be completely ignored. As the checks are skipped, the server may operate faster in this mode.

An example configuration that disables reservation looks like follows:

"Dhcp4": {
    "subnet4": [
    {
        "subnet": "192.0.2.0/24",
        "reservation-mode": "disabled",
        ...
    }
    ]
}

Another aspect of the host reservations are the different types of identifiers. Kea 1.1.0 supports four types of identifiers (hw-address, duid, client-id and circuit-id), but more identifier types are likely to be added in the future. This is beneficial from a usability perspective. However, there is a drawback. For each incoming packet Kea has to to extract each identifier type and then query the database to see if there is a reservation done by this particular identifier. If nothing is found, the next identifier is extracted and the next query is issued. This process continues until either a reservation is found or all identifier types have been checked. Over time with an increasing number of supported identifier types, Kea would become slower and slower.

To address this problem, a parameter called host-reservation-identifiers has been introduced. It takes a list of identifier types as a parameter. Kea will check only those identifier types enumerated in host-reservation-identifiers. From a performance perspective the number of identifier types should be kept to a minimum, ideally limited to one. If your deployment uses several reservation types, please enumerate them from most to least frequently used as this increases the chances of Kea finding the reservation using the fewest number of queries. An example of host reservation identifiers looks as follows:

"host-reservation-identifiers": [ "circuit-id", "hw-address", "duid", "client-id" ],
"subnet4": [
    {
        "subnet": "192.0.2.0/24",
        ...
    }
]

If not specified, the default value is:

"host-reservation-identifiers": [ "hw-address", "duid", "circuit-id", "client-id" ]

7.4. Server Identifier in DHCPv4

The DHCPv4 protocol uses a "server identifier" to allow clients to discriminate between several servers present on the same link: this value is an IPv4 address of the server. The server chooses the IPv4 address of the interface on which the message from the client (or relay) has been received. A single server instance will use multiple server identifiers if it is receiving queries on multiple interfaces.

Currently there is no mechanism to override the default server identifiers by an administrator. In the future, the configuration mechanism will be used to specify the custom server identifier.

7.5. How the DHCPv4 Server Selects a Subnet for the Client

The DHCPv4 server differentiates between the directly connected clients, clients trying to renew leases and clients sending their messages through relays. For directly connected clients, the server will check the configuration for the interface on which the message has been received and, if the server configuration doesn't match any configured subnet, the message is discarded.

Assuming that the server's interface is configured with the IPv4 address 192.0.2.3, the server will only process messages received through this interface from a directly connected client if there is a subnet configured to which this IPv4 address belongs, e.g. 192.0.2.0/24. The server will use this subnet to assign IPv4 address for the client.

The rule above does not apply when the client unicasts its message, i.e. is trying to renew its lease. Such a message is accepted through any interface. The renewing client sets ciaddr to the currently used IPv4 address. The server uses this address to select the subnet for the client (in particular, to extend the lease using this address).

If the message is relayed it is accepted through any interface. The giaddr set by the relay agent is used to select the subnet for the client.

It is also possible to specify a relay IPv4 address for a given subnet. It can be used to match incoming packets into a subnet in uncommon configurations, e.g. shared subnets. See Section 7.5.1, “Using a Specific Relay Agent for a Subnet†for details.

Note

The subnet selection mechanism described in this section is based on the assumption that client classification is not used. The classification mechanism alters the way in which a subnet is selected for the client, depending on the classes to which the client belongs.

7.5.1. Using a Specific Relay Agent for a Subnet

A relay has to have an interface connected to the link on which the clients are being configured. Typically the relay has an IPv4 address configured on that interface that belongs to the subnet from which the server will assign addresses. In the typical case, the server is able to use the IPv4 address inserted by the relay (in the giaddr field of the DHCPv4 packet) to select the appropriate subnet.

However, that is not always the case. In certain uncommon — but valid — deployments, the relay address may not match the subnet. This usually means that there is more than one subnet allocated for a given link. The two most common examples where this is the case are long lasting network renumbering (where both old and new address space is still being used) and a cable network. In a cable network both cable modems and the devices behind them are physically connected to the same link, yet they use distinct addressing. In such a case, the DHCPv4 server needs additional information (the IPv4 address of the relay) to properly select an appropriate subnet.

The following example assumes that there is a subnet 192.0.2.0/24 that is accessible via a relay that uses 10.0.0.1 as its IPv4 address. The server will be able to select this subnet for any incoming packets that came from a relay that has an address in 192.0.2.0/24 subnet. It will also select that subnet for a relay with address 10.0.0.1.

"Dhcp4": {
    "subnet4": [
        {
            "subnet": "192.0.2.0/24",
            "pools": [ { "pool": "192.0.2.10 - 192.0.2.20" } ],
            "relay": {
                "ip-address": "10.0.0.1"
            },
            ...
        }
    ],
    ...
}

7.5.2. Segregating IPv4 Clients in a Cable Network

In certain cases, it is useful to mix relay address information, introduced in Section 7.5.1, “Using a Specific Relay Agent for a Subnet†with client classification, explained in Chapter 12, Client Classification. One specific example is cable network, where typically modems get addresses from a different subnet than all devices connected behind them.

Let us assume that there is one CMTS (Cable Modem Termination System) with one CM MAC (a physical link that modems are connected to). We want the modems to get addresses from the 10.1.1.0/24 subnet, while everything connected behind modems should get addresses from another subnet (192.0.2.0/24). The CMTS that acts as a relay uses address 10.1.1.1. The following configuration can serve that configuration:

"Dhcp4": {
    "subnet4": [
        {
            "subnet": "10.1.1.0/24",
            "pools":  [ { "pool": "10.1.1.2 - 10.1.1.20" } ],
            "client-class" "docsis3.0",
            "relay": {
                "ip-address": "10.1.1.1"
            }
        },
        {
            "subnet": "192.0.2.0/24",
            "pools": [ { "pool": "192.0.2.10 - 192.0.2.20" } ],
            "relay": {
                "ip-address": "10.1.1.1"
            }
        }
    ],
    ...
}

7.6. Duplicate Addresses (DHCPDECLINE Support)

The DHCPv4 server is configured with a certain pool of addresses that it is expected to hand out to the DHCPv4 clients. It is assumed that the server is authoritative and has complete jurisdiction over those addresses. However, due to various reasons, such as misconfiguration or a faulty client implementation that retains its address beyond the valid lifetime, there may be devices connected that use those addresses without the server's approval or knowledge.

Such an unwelcome event can be detected by legitimate clients (using ARP or ICMP Echo Request mechanisms) and reported to the DHCPv4 server using a DHCPDECLINE message. The server will do a sanity check (if the client declining an address really was supposed to use it), and then will conduct a clean up operation. Any DNS entries related to that address will be removed, the fact will be logged and hooks will be triggered. After that is done, the address will be marked as declined (which indicates that it is used by an unknown entity and thus not available for assignment to anyone) and a probation time will be set on it. Unless otherwise configured, the probation period lasts 24 hours. After that period, the server will recover the lease (i.e. put it back into the available state) and the address will be available for assignment again. It should be noted that if the underlying issue of a misconfigured device is not resolved, the duplicate address scenario will repeat. On the other hand, it provides an opportunity to recover from such an event automatically, without any sysadmin intervention.

To configure the decline probation period to a value other than the default, the following syntax can be used:

  "Dhcp4": {
    "decline-probation-period": 3600,
    "subnet4": [ ... ],
    ...
}

The parameter is expressed in seconds, so the example above will instruct the server to recycle declined leases after an hour.

There are several statistics and hook points associated with the Decline handling procedure. The lease4_decline hook is triggered after the incoming DHCPDECLINE message has been sanitized and the server is about to decline the lease. The declined-addresses statistic is increased after the hook returns (both global and subnet specific variants). (See Section 7.7, “Statistics in the DHCPv4 Server†and Chapter 13, Hooks Libraries for more details on DHCPv4 statistics and Kea hook points.)

Once the probation time elapses, the declined lease is recovered using the standard expired lease reclamation procedure, with several additional steps. In particular, both declined-addresses statistics (global and subnet specific) are decreased. At the same time, reclaimed-declined-addresses statistics (again in two variants, global and subnet specific) are increased.

Note about statistics: The server does not decrease the assigned-addresses statistics when a DHCPDECLINE is received and processed successfully. While technically a declined address is no longer assigned, the primary usage of the assigned-addresses statistic is to monitor pool utilization. Most people would forget to include declined-addresses in the calculation, and simply do assigned-addresses/total-addresses. This would have a bias towards under-representing pool utilization. As this has a potential for major issues, we decided not to decrease assigned addresses immediately after receiving DHCPDECLINE, but to do it later when we recover the address back to the available pool.

7.7. Statistics in the DHCPv4 Server

Note

This section describes DHCPv4-specific statistics. For a general overview and usage of statistics, see Chapter 14, Statistics.

The DHCPv4 server supports the following statistics:

Table 7.5. DHCPv4 Statistics

StatisticData TypeDescription
pkt4-receivedinteger Number of DHCPv4 packets received. This includes all packets: valid, bogus, corrupted, rejected etc. This statistic is expected to grow rapidly.
pkt4-discover-receivedinteger Number of DHCPDISCOVER packets received. This statistic is expected to grow. Its increase means that clients that just booted started their configuration process and their initial packets reached your server.
pkt4-offer-receivedinteger Number of DHCPOFFER packets received. This statistic is expected to remain zero at all times, as DHCPOFFER packets are sent by the server and the server is never expected to receive them. Non-zero value indicates an error. One likely cause would be a misbehaving relay agent that incorrectly forwards DHCPOFFER messages towards the server, rather back to the clients.
pkt4-request-receivedinteger Number of DHCPREQUEST packets received. This statistic is expected to grow. Its increase means that clients that just booted received server's response (DHCPOFFER), accepted it and now requesting an address (DHCPREQUEST).
pkt4-ack-receivedinteger Number of DHCPACK packets received. This statistic is expected to remain zero at all times, as DHCPACK packets are sent by the server and the server is never expected to receive them. Non-zero value indicates an error. One likely cause would be a misbehaving relay agent that incorrectly forwards DHCPACK messages towards the server, rather back to the clients.
pkt4-nak-receivedinteger Number of DHCPNAK packets received. This statistic is expected to remain zero at all times, as DHCPNAK packets are sent by the server and the server is never expected to receive them. Non-zero value indicates an error. One likely cause would be a misbehaving relay agent that incorrectly forwards DHCPNAK messages towards the server, rather back to the clients.
pkt4-release-receivedinteger Number of DHCPRELEASE packets received. This statistic is expected to grow. Its increase means that clients that had an address are shutting down or stop using their addresses.
pkt4-decline-receivedinteger Number of DHCPDECLINE packets received. This statistic is expected to remain close to zero. Its increase means that a client that leased an address, but discovered that the address is currently used by an unknown device in your network.
pkt4-inform-receivedinteger Number of DHCPINFORM packets received. This statistic is expected to grow. Its increase means that there are clients that either do not need an address or already have an address and are interested only in getting additional configuration parameters.
pkt4-unknown-receivedinteger Number of packets received of an unknown type. Non-zero value of this statistic indicates that the server received a packet that it wasn't able to recognize: either with unsupported type or possibly malformed (without message type option).
pkt4-sentinteger Number of DHCPv4 packets sent. This statistic is expected to grow every time the server transmits a packet. In general, it should roughly match pkt4-received, as most incoming packets cause server to respond. There are exceptions (e.g. DHCPRELEASE), so do not worry, if it is lesser than pkt4-received.
pkt4-offer-sentinteger Number of DHCPOFFER packets sent. This statistic is expected to grow in most cases after a DHCPDISCOVER is processed. There are certain uncommon, but valid cases where incoming DHCPDISCOVER is dropped, but in general this statistic is expected to be close to pkt4-discover-received.
pkt4-ack-sentinteger Number of DHCPACK packets sent. This statistic is expected to grow in most cases after a DHCPREQUEST is processed. There are certain cases where DHCPNAK is sent instead. In general, the sum of pkt4-ack-sent and pkt4-nak-sent should be close to pkt4-request-received.
pkt4-nak-sentinteger Number of DHCPNAK packets sent. This statistic is expected to grow when the server chooses to not honor the address requested by a client. In general, the sum of pkt4-ack-sent and pkt4-nak-sent should be close to pkt4-request-received.
pkt4-parse-failedinteger Number of incoming packets that could not be parsed. A non-zero value of this statistic indicates that the server received malformed or truncated packet. This may indicate problems in your network, faulty clients or a bug in the server.
pkt4-receive-dropinteger Number of incoming packets that were dropped. The exact reason for dropping packets is logged, but the most common reasons may be: an unacceptable packet type, direct responses are forbidden, or the server-id sent by the client does not match the server's server-id.
subnet[id].total-addressesintegerThe total number of addresses available for DHCPv4 management. In other words, this is the sum of all addresses in all configured pools. This statistic changes only during configuration changes. Note it does not take into account any addresses that may be reserved due to host reservation. The id is the subnet-id of a given subnet. This statistic is exposed for each subnet separately. This statistic is reset during reconfiguration event.
subnet[id].assigned-addressesintegerThis statistic shows the number of assigned addresses in a given subnet. It increases every time a new lease is allocated (as a result of receiving a DHCPREQUEST message) and is decreased every time a lease is released (a DHCPRELEASE message is received) or expires. The id is the subnet-id of the subnet. This statistic is exposed for each subnet separately. This statistic is reset during reconfiguration event.
declined-addressesinteger This statistic shows the number of IPv4 addresses that are currently declined, so counting the number of leases currently unavailable. Once a lease is recovered, this statistic will be decreased. Ideally, this statistic should be zero. If this statistic is non-zero (or worse increasing), a network administrator should investigate if there is a misbehaving device in his network. This is a global statistic that covers all subnets.
subnet[id].declined-addressesinteger This statistic shows the number of IPv4 addresses that are currently declined in a given subnet, so is a count of the number of leases currently unavailable. Once a lease is recovered, this statistic will be decreased. Ideally, this statistic should be zero. If this statistic is non-zero (or worse increasing), a network administrator should investigate if there is a misbehaving device in his network. The id is the subnet-id of a given subnet. This statistic is exposed for each subnet separately.
reclaimed-declined-addressesinteger This statistic shows the number of IPv4 addresses that were declined, but have now been recovered. Unlike declined-addresses, this statistic never decreases. It can be used as a long term indicator of how many actual valid Declines were processed and recovered from. This is a global statistic that covers all subnets.
subnet[id].reclaimed-declined-addressesinteger This statistic shows the number of IPv4 addresses that were declined, but have now been recovered. Unlike declined-addresses, this statistic never decreases. It can be used as a long term indicator of how many actual valid Declines were processed and recovered from. The id is the subnet-id of a given subnet. This statistic is exposed for each subnet separately.

7.8. Management API for the DHCPv4 Server

The management API allows the issuing of specific management commands, such as statistics retrieval, reconfiguration or shutdown. For more details, see Chapter 15, Management API. Currently the only supported communication channel type is UNIX stream socket. By default there are no sockets open. To instruct Kea to open a socket, the following entry in the configuration file can be used:

"Dhcp4": {
    "control-socket": {
        "socket-type": "unix",
        "socket-name": "/path/to/the/unix/socket"
    },

    "subnet4": [
        ...
    ],
    ...
}

The length of the path specified by the socket-name parameter is restricted by the maximum length for the unix socket name on your operating system, i.e. the size of the sun_path field in the sockaddr_un structure, decreased by 1. This value varies on different operating systems between 91 and 107 characters. Typical values are 107 on Linux and 103 on FreeBSD.

Communication over control channel is conducted using JSON structures. See the Control Channel section in the Kea Developer's Guide for more details.

The DHCPv4 server supports statistic-get, statistic-reset, statistic-remove, statistic-get-all, statistic-reset-all and statistic-remove-all, specified in Section 14.3, “Commands for Manipulating Statisticsâ€. It also supports list-commands and shutdown, specified in Section 15.3.2, “list-commands†and Section 15.3.3, “shutdownâ€, respectively.

7.9. Supported DHCP Standards

The following standards are currently supported:

  • Dynamic Host Configuration Protocol, RFC 2131: Supported messages are DHCPDISCOVER (1), DHCPOFFER (2), DHCPREQUEST (3), DHCPRELEASE (7), DHCPINFORM (8), DHCPACK (5), and DHCPNAK(6).
  • DHCP Options and BOOTP Vendor Extensions, RFC 2132: Supported options are: PAD (0), END(255), Message Type(53), DHCP Server Identifier (54), Domain Name (15), DNS Servers (6), IP Address Lease Time (51), Subnet mask (1), and Routers (3).
  • DHCP Relay Agent Information Option, RFC 3046: Relay Agent Information option is supported.
  • Vendor-Identifying Vendor Options for Dynamic Host Configuration Protocol version 4, RFC 3925: Vendor-Identifying Vendor Class and Vendor-Identifying Vendor-Specific Information options are supported.
  • Client Identifier Option in DHCP Server Replies, RFC 6842: Server by default sends back client-id option. That capability may be disabled. See Section 7.2.17, “Echoing Client-ID (RFC 6842)†for details.

7.10. DHCPv4 Server Limitations

These are the current limitations of the DHCPv4 server software. Most of them are reflections of the current stage of development and should be treated as “not implemented yetâ€, rather than actual limitations. However, some of them are implications of the design choices made. Those are clearly marked as such.

  • BOOTP (RFC 951) is not supported. This is a design choice: BOOTP support is not planned.
  • On Linux and BSD system families the DHCP messages are sent and received over the raw sockets (using LPF and BPF) and all packet headers (including data link layer, IP and UDP headers) are created and parsed by Kea, rather than the system kernel. Currently, Kea can only parse the data link layer headers with a format adhering to IEEE 802.3 standard and assumes this data link layer header format for all interfaces. Hence, Kea will fail to work on interfaces which use different data link layer header formats (e.g. Infiniband).
  • The DHCPv4 server does not verify that assigned address is unused. According to RFC 2131, the allocating server should verify that address is not used by sending ICMP echo request.

Chapter 8. The DHCPv6 Server

Table of Contents

8.1. Starting and Stopping the DHCPv6 Server
8.2. DHCPv6 Server Configuration
8.2.1. Introduction
8.2.2. Lease Storage
8.2.3. Hosts Storage
8.2.4. Interface Selection
8.2.5. IPv6 Subnet Identifier
8.2.6. Unicast Traffic Support
8.2.7. Subnet and Address Pool
8.2.8. Subnet and Prefix Delegation Pools
8.2.9. Standard DHCPv6 Options
8.2.10. Custom DHCPv6 Options
8.2.11. DHCPv6 Vendor-Specific Options
8.2.12. Nested DHCPv6 Options (Custom Option Spaces)
8.2.13. Unspecified Parameters for DHCPv6 Option Configuration
8.2.14. IPv6 Subnet Selection
8.2.15. Rapid Commit
8.2.16. DHCPv6 Relays
8.2.17. Relay-Supplied Options
8.2.18. Client Classification in DHCPv6
8.2.19. DDNS for DHCPv6
8.2.20. DHCPv4-over-DHCPv6: DHCPv6 Side
8.3. Host Reservation in DHCPv6
8.3.1. Address/Prefix Reservation Types
8.3.2. Conflicts in DHCPv6 Reservations
8.3.3. Reserving a Hostname
8.3.4. Including Specific DHCPv6 Options in Reservations
8.3.5. Reserving Client Classes in DHCPv6
8.3.6. Storing Host Reservations in MySQL or PostgreSQL
8.3.7. Storing Host Reservations in CQL (Cassandra)
8.3.8. Fine Tuning DHCPv6 Host Reservation
8.4. Server Identifier in DHCPv6
8.5. Stateless DHCPv6 (Information-Request Message)
8.6. Support for RFC 7550
8.7. Using Specific Relay Agent for a Subnet
8.8. Segregating IPv6 Clients in a Cable Network
8.9. MAC/Hardware Addresses in DHCPv6
8.10. Duplicate Addresses (DECLINE Support)
8.11. Statistics in the DHCPv6 Server
8.12. Management API for the DHCPv6 Server
8.13. Supported DHCPv6 Standards
8.14. DHCPv6 Server Limitations

8.1. Starting and Stopping the DHCPv6 Server

It is recommended that the Kea DHCPv6 server be started and stopped using keactrl (described in Chapter 6, Managing Kea with keactrl). However, it is also possible to run the server directly: it accepts the following command-line switches:

  • -c file - specifies the configuration file. This is the only mandatory switch.
  • -d - specifies whether the server logging should be switched to verbose mode. In verbose mode, the logging severity and debuglevel specified in the configuration file are ignored and "debug" severity and the maximum debuglevel (99) are assumed. The flag is convenient, for temporarily switching the server into maximum verbosity, e.g. when debugging.
  • -p port - specifies UDP port on which the server will listen. This is only useful during testing, as a DHCPv6 server listening on ports other than the standard ones will not be able to handle regular DHCPv6 queries.
  • -v - prints out the Kea version and exits.
  • -V - prints out the Kea extended version with additional parameters and exits. The listing includes the versions of the libraries dynamically linked to Kea.
  • -W - prints out the Kea configuration report and exits. The report is a copy of the config.report file produced by ./configure: it is embedded in the executable binary.

The config.report may also be accessed more directly. The following command may be used to extract this information. The binary path may be found in the install directory or in the .libs subdirectory in the source tree. For example kea/src/bin/dhcp6/.libs/kea-dhcp6.

strings path/kea-dhcp6 | sed -n 's/;;;; //p'

On start-up, the server will detect available network interfaces and will attempt to open UDP sockets on all interfaces mentioned in the configuration file. Since the DHCPv6 server opens privileged ports, it requires root access. Make sure you run this daemon as root.

During startup the server will attempt to create a PID file of the form: localstatedir]/[conf name].kea-dhcp6.pid where:

  • localstatedir: The value as passed into the build configure script. It defaults to "/usr/local/var". Note that this value may be overridden at run time by setting the environment variable KEA_PIDFILE_DIR. This is intended primarily for testing purposes.
  • conf name: The configuration file name used to start the server, minus all preceding path and file extension. For example, given a pathname of "/usr/local/etc/kea/myconf.txt", the portion used would be "myconf".

If the file already exists and contains the PID of a live process, the server will issue a DHCP6_ALREADY_RUNNING log message and exit. It is possible, though unlikely, that the file is a remnant of a system crash and the process to which the PID belongs is unrelated to Kea. In such a case it would be necessary to manually delete the PID file.

The server can be stopped using the kill command. When running in a console, the server can be shut down by pressing ctrl-c. It detects the key combination and shuts down gracefully.

8.2. DHCPv6 Server Configuration

8.2.1. Introduction

This section explains how to configure the DHCPv6 server using the Kea configuration backend. (Kea configuration using any other backends is outside of scope of this document.) Before DHCPv6 is started, its configuration file has to be created. The basic configuration is as follows:

{
# DHCPv6 configuration starts on the next line
"Dhcp6": {

# First we set up global values
    "valid-lifetime": 4000,
    "renew-timer": 1000,
    "rebind-timer": 2000,
    "preferred-lifetime": 3000,

# Next we setup the interfaces to be used by the server.
    "interfaces-config": {
        "interfaces": [ "eth0" ]
    },

# And we specify the type of lease database
    "lease-database": {
        "type": "memfile",
        "persist": true,
        "name": "/var/kea/dhcp6.leases"
    },

# Finally, we list the subnets from which we will be leasing addresses.
    "subnet6": [
        {
            "subnet": "2001:db8:1::/64",
            "pools": [
                 {
                     "pool": "2001:db8:1::1-2001:db8:1::ffff"
                 }
             ]
        }
    ]
# DHCPv6 configuration ends with the next line
}

} 

The following paragraphs provide a brief overview of the parameters in the above example together with their format. Subsequent sections of this chapter go into much greater detail for these and other parameters.

The lines starting with a hash (#) are comments and are ignored by the server; they do not impact its operation in any way.

The configuration starts in the first line with the initial opening curly bracket (or brace). Each configuration consists of one or more objects. In this specific example, we have only one object, called Dhcp6. This is a simplified configuration, as usually there will be additional objects, like Logging or DhcpDns, but we omit them now for clarity. The Dhcp6 configuration starts with the "Dhcp6": { line and ends with the corresponding closing brace (in the above example, the brace after the last comment). Everything defined between those lines is considered to be the Dhcp6 configuration.

In the general case, the order in which those parameters appear does not matter. There are two caveats here though. The first one is to remember that the configuration file must be well formed JSON. That means that parameters for any given scope must be separated by a comma and there must not be a comma after the last parameter. When reordering a configuration file, keep in mind that moving a parameter to or from the last position in a given scope may also require moving the comma. The second caveat is that it is uncommon — although legal JSON — to repeat the same parameter multiple times. If that happens, the last occurrence of a given parameter in a given scope is used while all previous instances are ignored. This is unlikely to cause any confusion as there are no real life reasons to keep multiple copies of the same parameter in your configuration file.

Moving onto the DHCPv6 configuration elements, the very first few elements define some global parameters. valid-lifetime defines for how long the addresses (leases) given out by the server are valid. If nothing changes, a client that got an address is allowed to use it for 4000 seconds. (Note that integer numbers are specified as is, without any quotes around them.) The address will become deprecated in 3000 seconds (clients are allowed to keep old connections, but can't use this address for creating new connections). renew-timer and rebind-timer are values that define T1 and T2 timers that govern when the client will begin the renewal and rebind procedures.

The interfaces-config map specifies the server configuration concerning the network interfaces, on which the server should listen to the DHCP messages. The interfaces parameter specifies a list of network interfaces on which the server should listen. Lists are opened and closed with square brackets, with elements separated by commas. Had we wanted to listen on two interfaces, the interfaces-config would look like this:

"interfaces-config": {
    "interfaces": [ "eth0", "eth1" ]
},

The next couple of lines define the lease database, the place where the server stores its lease information. This particular example tells the server to use memfile, which is the simplest (and fastest) database backend. It uses an in-memory database and stores leases on disk in a CSV file. This is a very simple configuration. Usually the lease database configuration is more extensive and contains additional parameters. Note that lease-database is an object and opens up a new scope, using an opening brace. Its parameters (just one in this example - type) follow. Had there been more than one, they would be separated by commas. This scope is closed with a closing brace. As more parameters for the Dhcp6 definition follow, a trailing comma is present.

Finally, we need to define a list of IPv6 subnets. This is the most important DHCPv6 configuration structure as the server uses that information to process clients' requests. It defines all subnets from which the server is expected to receive DHCP requests. The subnets are specified with the subnet6 parameter. It is a list, so it starts and ends with square brackets. Each subnet definition in the list has several attributes associated with it, so it is a structure and is opened and closed with braces. At minimum, a subnet definition has to have at least two parameters: subnet (that defines the whole subnet) and pools (which is a list of dynamically allocated pools that are governed by the DHCP server).

The example contains a single subnet. Had more than one been defined, additional elements in the subnet6 parameter would be specified and separated by commas. For example, to define two subnets, the following syntax would be used:

"subnet6": [
    {
        "pools": [ { "pool": "2001:db8:1::/112" } ],
        "subnet": "2001:db8:1::/64"
    },
    {
        "pools": [ { "pool": "2001:db8:2::1-2001:db8:2::ffff" } ],
        "subnet": "2001:db8:2::/64"
    }
]

Note that indentation is optional and is used for aesthetic purposes only. In some cases in may be preferable to use more compact notation.

After all parameters are specified, we have two contexts open: global and Dhcp6, hence we need two closing curly brackets to close them. In a real life configuration file there most likely would be additional components defined such as Logging or DhcpDdns, so the closing brace would be followed by a comma and another object definition.

8.2.2. Lease Storage

All leases issued by the server are stored in the lease database. Currently there are four database backends available: memfile (which is the default backend), MySQL, PostgreSQL and Cassandra.

8.2.2.1. Memfile - Basic Storage for Leases

The server is able to store lease data in different repositories. Larger deployments may elect to store leases in a database. Section 8.2.2.2, “Lease Database Configuration†describes this option. In typical smaller deployments though, the server will store lease information in a CSV file rather than a database. As well as requiring less administration, an advantage of using a file for storage is that it eliminates a dependency on third-party database software.

The configuration of the file backend (Memfile) is controlled through the Dhcp6/lease-database parameters. The type parameter is mandatory and it specifies which storage for leases the server should use. The value of "memfile" indicates that the file should be used as the storage. The following list gives additional, optional, parameters that can be used to configure the Memfile backend.

  • persist: controls whether the new leases and updates to existing leases are written to the file. It is strongly recommended that the value of this parameter is set to true at all times, during the server's normal operation. Not writing leases to disk will mean that if a server is restarted (e.g. after a power failure), it will not know what addresses have been assigned. As a result, it may hand out addresses to new clients that are already in use. The value of false is mostly useful for performance testing purposes. The default value of the persist parameter is true, which enables writing lease updates to the lease file.
  • name: specifies an absolute location of the lease file in which new leases and lease updates will be recorded. The default value for this parameter is "[kea-install-dir]/var/kea/kea-leases6.csv" .
  • lfc-interval: specifies the interval in seconds, at which the server will perform a lease file cleanup (LFC). This removes redundant (historical) information from the lease file and effectively reduces the lease file size. The cleanup process is described in more detailed fashion further in this section. The default value of the lfc-interval is 0, which disables the LFC.

An example configuration of the Memfile backend is presented below:

"Dhcp6": {
    "lease-database": {
        "type": "memfile",
        "persist": true,
        "name": "/tmp/kea-leases6.csv",
        "lfc-interval": 1800
    }
}

This configuration selects the /tmp/kea-leases6.csv as the storage for lease information and enables persistence (writing lease updates to this file). It also configures the backend perform the periodic cleanup of the lease files, executed every 30 minutes.

It is important to know how the lease file contents are organized to understand why the periodic lease file cleanup is needed. Every time the server updates a lease or creates a new lease for the client, the new lease information must be recorded in the lease file. For performance reasons, the server does not update the existing client's lease in the file, as it would potentially require rewriting the entire file. Instead, it simply appends the new lease information to the end of the file: the previous lease entries for the client are not removed. When the server loads leases from the lease file, e.g. at the server startup, it assumes that the latest lease entry for the client is the valid one. The previous entries are discarded. This means that the server can re-construct the accurate information about the leases even though there may be many lease entries for each client. However, storing many entries for each client results in bloated lease file and impairs the performance of the server's startup and reconfiguration as it needs to process a larger number of lease entries.

Lease file cleanup (LFC) removes all previous entries for each client and leaves only the latest ones. The interval at which the cleanup is performed is configurable, and it should be selected according to the frequency of lease renewals initiated by the clients. The more frequent the renewals, the smaller the value of lfc-interval should be. Note however, that the LFC takes time and thus it is possible (although unlikely) that new cleanup is started while the previous cleanup instance is still running, if the lfc-interval is too short. The server would recover from this by skipping the new cleanup when it detects that the previous cleanup is still in progress. But it implies that the actual cleanups will be triggered more rarely than configured. Moreover, triggering a new cleanup adds an overhead to the server which will not be able to respond to new requests for a short period of time when the new cleanup process is spawned. Therefore, it is recommended that the lfc-interval value is selected in a way that would allow for the LFC to complete the cleanup before a new cleanup is triggered.

Lease file cleanup is performed by a separate process (in background) to avoid a performance impact on the server process. In order to avoid the conflicts between two processes both using the same lease files, the LFC process operates on the copy of the original lease file, rather than on the lease file used by the server to record lease updates. There are also other files being created as a side effect of the lease file cleanup. The detailed description of the LFC is located on the Kea wiki: http://kea.isc.org/wiki/LFCDesign.

8.2.2.2. Lease Database Configuration

Note

Lease database access information must be configured for the DHCPv6 server, even if it has already been configured for the DHCPv4 server. The servers store their information independently, so each server can use a separate database or both servers can use the same database.

Lease database configuration is controlled through the Dhcp6/lease-database parameters. The type of the database must be set to "memfile", "mysql", "postgresql" or "cql", e.g.

"Dhcp6": { "lease-database": { "type": "mysql", ... }, ... }

Next, the name of the database is to hold the leases must be set: this is the name used when the database was created (see Section 4.3.2.1, “First Time Creation of the MySQL Databaseâ€, Section 4.3.3.1, “First Time Creation of the PostgreSQL Database†or Section 4.3.4.1, “First Time Creation of the Cassandra Databaseâ€).

"Dhcp6": { "lease-database": { "name": "database-name" , ... }, ... }

If the database is located on a different system to the DHCPv6 server, the database host name must also be specified. (It should be noted that this configuration may have a severe impact on server performance.):

"Dhcp6": { "lease-database": { "host": remote-host-name, ... }, ... }

The usual state of affairs will be to have the database on the same machine as the DHCPv6 server. In this case, set the value to the empty string:

"Dhcp6": { "lease-database": { "host" : "", ... }, ... }

Should the database be located on a different system, you may need to specify a longer interval for the connection timeout:

"Dhcp6": { "lease-database": { "connect-timeout" : timeout-in-seconds, ... }, ... }

The default value of five seconds should be more than adequate for local connections. If a timeout is given though, it should be an integer greater than zero.

Finally, the credentials of the account under which the server will access the database should be set:

"Dhcp6": { "lease-database": { "user": "user-name",
                               "password": "password",
                              ... },
           ... }

If there is no password to the account, set the password to the empty string "". (This is also the default.)

8.2.3. Hosts Storage

Kea is also able to store information about host reservations in the database. The hosts database configuration uses the same syntax as the lease database. In fact, a Kea server opens independent connections for each purpose, be it lease or hosts information. This arrangement gives the most flexibility. Kea can be used to keep leases and host reservations separately, but can also point to the same database. Currently the supported hosts database types are MySQL and PostgreSQL. The Cassandra backend does not support host reservations yet.

Please note that usage of hosts storage is optional. A user can define all host reservations in the configuration file. That is the recommended way if the number of reservations is small. However, when the number of reservations grows it's more convenient to use host storage. Please note that both storage methods (configuration file and one of the supported databases) can be used together. If hosts are defined in both places, the definitions from the configuration file are checked first and external storage is checked later, if necessary.

8.2.3.1. DHCPv6 Hosts Database Configuration

Hosts database configuration is controlled through the Dhcp6/hosts-database parameters. If enabled, the type of the database must be set to "mysql" or "postgresql". Other hosts backends may be added in later version of Kea.

"Dhcp6": { "hosts-database": { "type": "mysql", ... }, ... }

Next, the name of the database to hold the reservations must be set: this is the name used when the database was created (see Section 4.3, “Supported Databases†for instructions how to setup desired database type).

"Dhcp6": { "hosts-database": { "name": "database-name" , ... }, ... }

If the database is located on a different system than the DHCPv6 server, the database host name must also be specified. (Again it should be noted that this configuration may have a severe impact on server performance):

"Dhcp6": { "hosts-database": { "host": remote-host-name, ... }, ... }

The usual state of affairs will be to have the database on the same machine as the DHCPv6 server. In this case, set the value to the empty string:

"Dhcp6": { "hosts-database": { "host" : "", ... }, ... }

Finally, the credentials of the account under which the server will access the database should be set:

"Dhcp6": { "hosts-database": { "user": "user-name",
                               "password": "password",
                              ... },
           ... }

If there is no password to the account, set the password to the empty string "". (This is also the default.)

8.2.3.2. Using Read-Only Databases for Host Reservations

In some deployments the database user whose name is specified in the database backend configuration may not have write privileges to the database. This is often required by the policy within a given network to secure the data from being unintentionally modified. In many cases administrators have inventory databases deployed, which contain substantially more information about the hosts than static reservations assigned to them. The inventory database can be used to create a view of a Kea hosts database and such view is often read only.

Kea host database backends operate with an implicit configuration to both read from and write to the database. If the database user does not have write access to the host database, the backend will fail to start and the server will refuse to start (or reconfigure). However, if access to a read only host database is required for retrieving reservations for clients and/or assign specific addresses and options, it is possible to explicitly configure Kea to start in "read-only" mode. This is controlled by the readonly boolean parameter as follows:

"Dhcp6": { "hosts-database": { "readonly": true, ... }, ... }

Setting this parameter to false would configure the database backend to operate in "read-write" mode, which is also a default configuration if the parameter is not specified.

Note

The readonly parameter is currently only supported for MySQL and PostgreSQL databases.

8.2.4. Interface Selection

The DHCPv6 server has to be configured to listen on specific network interfaces. The simplest network interface configuration instructs the server to listen on all available interfaces:

"Dhcp6": {
    "interfaces-config": {
        "interfaces": [ "*" ]
    }
    ...
}

The asterisk plays the role of a wildcard and means "listen on all interfaces". However, it is usually a good idea to explicitly specify interface names:

"Dhcp6": {
    "interfaces-config": {
        "interfaces": [ "eth1", "eth3" ]
    },
    ...
}
  

It is possible to use wildcard interface name (asterisk) concurrently with the actual interface names:

"Dhcp6": {
    "interfaces-config": {
        "interfaces": [ "eth1", "eth3", "*" ]
    },
    ...
}
  

It is anticipated that this will form of usage only be used where it is desired to temporarily override a list of interface names and listen on all interfaces.

8.2.5. IPv6 Subnet Identifier

The subnet identifier is a unique number associated with a particular subnet. In principle, it is used to associate clients' leases with their respective subnets. When a subnet identifier is not specified for a subnet being configured, it will be automatically assigned by the configuration mechanism. The identifiers are assigned from 1 and are monotonically increased for each subsequent subnet: 1, 2, 3 ....

If there are multiple subnets configured with auto-generated identifiers and one of them is removed, the subnet identifiers may be renumbered. For example: if there are four subnets and the third is removed the last subnet will be assigned the identifier that the third subnet had before removal. As a result, the leases stored in the lease database for subnet 3 are now associated with subnet 4, something that may have unexpected consequences. It is planned to implement a mechanism to preserve auto-generated subnet ids in a future version of Kea. However, the only remedy for this issue at present is to manually specify a unique identifier for each subnet.

The following configuration will assign the specified subnet identifier to the newly configured subnet:

"Dhcp6": {
    "subnet6": [
        {
            "subnet": "2001:db8:1::/64",
            "id": 1024,
            ...
        }
    ]
}

This identifier will not change for this subnet unless the "id" parameter is removed or set to 0. The value of 0 forces auto-generation of the subnet identifier.

8.2.6. Unicast Traffic Support

When the DHCPv6 server starts, by default it listens to the DHCP traffic sent to multicast address ff02::1:2 on each interface that it is configured to listen on (see Section 8.2.4, “Interface Selectionâ€). In some cases it is useful to configure a server to handle incoming traffic sent to the global unicast addresses as well. The most common reason for this is to have relays send their traffic to the server directly. To configure the server to listen on a specific unicast address, nn interface name can be optionally followed by a slash, followed by the global unicast address on which the server should listen. The server listens to this address in addition to normal link-local binding and listening on ff02::1:2 address. The sample configuration below shows how to listen on 2001:db8::1 (a global address) configured on the eth1 interface.

"Dhcp6": {
    "interfaces-config": {
        "interfaces": [ "eth1/2001:db8::1" ]
    },
    ...
    "option-data": [
        {
            "name": "unicast",
            "data": "2001:db8::1"
        } ],
    ...
}
 

This configuration will cause the server to listen on eth1 on the link-local address, the multicast group (ff02::1:2) and 2001:db8::1.

Usually unicast support is associated with a server unicast option which allows clients to send unicast messages to the server. The example above includes a server unicast option specification which will cause the client to send messages to the specified unicast address.

It is possible to mix interface names, wildcards and interface name/addresses in the list of interfaces. It is not possible however to specify more than one unicast address on a given interface.

Care should be taken to specify proper unicast addresses. The server will attempt to bind to the addresses specified without any additional checks. This approach has selected on purpose to allow the software to communicate over uncommon addresses if so desired.

8.2.7. Subnet and Address Pool

The main role of a DHCPv6 server is address assignment. For this, the server has to be configured with at least one subnet and one pool of dynamic addresses to be managed. For example, assume that the server is connected to a network segment that uses the 2001:db8:1::/64 prefix. The Administrator of that network has decided that addresses from range 2001:db8:1::1 to 2001:db8:1::ffff are going to be managed by the Dhcp6 server. Such a configuration can be achieved in the following way:

"Dhcp6": {
    "subnet6": [
       {
           "subnet": "2001:db8:1::/64",
           "pools": [
               {
                   "pool": "2001:db8:1::1-2001:db8:1::ffff"
               }
           ],
           ...
       }
    ]
}

Note that subnet is defined as a simple string, but the pools parameter is actually a list of pools: for this reason, the pool definition is enclosed in square brackets, even though only one range of addresses is specified.

Each pool is a structure that contains the parameters that describe a single pool. Currently there is only one parameter, pool, which gives the range of addresses in the pool. Additional parameters will be added in future releases of Kea.

It is possible to define more than one pool in a subnet: continuing the previous example, further assume that 2001:db8:1:0:5::/80 should also be managed by the server. It could be written as 2001:db8:1:0:5:: to 2001:db8:1::5:ffff:ffff:ffff, but typing so many 'f's is cumbersome. It can be expressed more simply as 2001:db8:1:0:5::/80. Both formats are supported by Dhcp6 and can be mixed in the pool list. For example, one could define the following pools:

"Dhcp6": {
    "subnet6": [
    {
        "subnet": "2001:db8:1::/64",
        "pools": [
            { "pool": "2001:db8:1::1-2001:db8:1::ffff" },
            { "pool": "2001:db8:1:05::/80" }
        ],
        ...
    }
    ]
}

White space in pool definitions is ignored, so spaces before and after the hyphen are optional. They can be used to improve readability.

The number of pools is not limited, but for performance reasons it is recommended to use as few as possible.

The server may be configured to serve more than one subnet. To add a second subnet, use a command similar to the following:

"Dhcp6": {
    "subnet6": [
    {
        "subnet": "2001:db8:1::/64",
        "pools": [
            { "pool": "2001:db8:1::1-2001:db8:1::ffff" }
        ]
    },
    {
        "subnet": "2001:db8:2::/64",
        "pools": [
            { "pool": "2001:db8:2::/64" }
        ]
    },

        ...
    ]
}

In this example, we allow the server to dynamically assign all addresses available in the whole subnet. Although rather wasteful, it is certainly a valid configuration to dedicate the whole /64 subnet for that purpose. Note that the Kea server does not preallocate the leases, so there is no danger in using gigantic address pools.

When configuring a DHCPv6 server using prefix/length notation, please pay attention to the boundary values. When specifying that the server can use a given pool, it will also be able to allocate the first (typically network address) address from that pool. For example, for pool 2001:db8:2::/64 the 2001:db8:2:: address may be assigned as well. If you want to avoid this, use the "min-max" notation.

8.2.8. Subnet and Prefix Delegation Pools

Subnets may also be configured to delegate prefixes, as defined in RFC 3633. A subnet may have one or more prefix delegation pools. Each pool has a prefixed address, which is specified as a prefix (prefix) and a prefix length (prefix-len), as well as a delegated prefix length (delegated-len). The delegated length must not be shorter (that is it must be numerically greater or equal) than the prefix length. If both the delegated and prefix lengths are equal, the server will be able to delegate only one prefix. The delegated prefix does not have to match the subnet prefix.

Below is a sample subnet configuration which enables prefix delegation for the subnet:

"Dhcp6": {
    "subnet6": [
        {
            "subnet": "2001:d8b:1::/64",
            "pd-pools": [
                {
                    "prefix": "3000:1::",
                    "prefix-len": 64,
                    "delegated-len": 96
                }
            ]
        }
    ],
    ...
}

8.2.9. Standard DHCPv6 Options

One of the major features of a DHCPv6 server is to provide configuration options to clients. Although there are several options that require special behavior, most options are sent by the server only if the client explicitly requests them. The following example shows how to configure DNS servers, one of the most frequently used options. Options specified in this way are considered global and apply to all configured subnets.

"Dhcp6": {
    "option-data": [
        {
           "name": "dns-servers",
           "code": 23,
           "space": "dhcp6",
           "csv-format": true,
           "data": "2001:db8::cafe, 2001:db8::babe"
        },
        ...
    ]
}

The option-data line creates a new entry in the option-data table. This table contains information on all global options that the server is supposed to configure in all subnets. The name line specifies the option name. (For a complete list of currently supported names, see Table 8.1, “List of Standard DHCPv6 Optionsâ€.) The next line specifies the option code, which must match one of the values from that list. The line beginning with space specifies the option space, which must always be set to "dhcp6" as these are standard DHCPv6 options. For other name spaces, including custom option spaces, see Section 8.2.12, “Nested DHCPv6 Options (Custom Option Spaces)â€. The following line specifies the format in which the data will be entered: use of CSV (comma separated values) is recommended. Finally, the data line gives the actual value to be sent to clients. Data is specified as normal text, with values separated by commas if more than one value is allowed.

Options can also be configured as hexadecimal values. If "csv-format" is set to false, the option data must be specified as a string of hexadecimal numbers. The following commands configure the DNS-SERVERS option for all subnets with the following addresses: 2001:db8:1::cafe and 2001:db8:1::babe.

"Dhcp6": {
    "option-data": [
        {
           "name": "dns-servers",
           "code": 23,
           "space": "dhcp6",
           "csv-format": false,
           "data": "2001 0DB8 0001 0000 0000 0000 0000 CAFE
                    2001 0DB8 0001 0000 0000 0000 0000 BABE"
        },
        ...
    ]
}

Note

The value for the setting of the "data" element is split across two lines in this example for clarity: when entering the command, the whole string should be entered on the same line.

Care should be taken to use proper encoding when using hexadecimal format as Kea's ability to validate data correctness in hexadecimal is limited.

Most of the parameters in the "option-data" structure are optional and can be omitted in some circumstances as discussed in the Section 8.2.13, “Unspecified Parameters for DHCPv6 Option Configurationâ€.

It is possible to override options on a per-subnet basis. If clients connected to most of your subnets are expected to get the same values of a given option, you should use global options: you can then override specific values for a small number of subnets. On the other hand, if you use different values in each subnet, it does not make sense to specify global option values (Dhcp6/option-data), rather you should set only subnet-specific values (Dhcp6/subnet[X]/option-data[Y]).

The following commands override the global DNS servers option for a particular subnet, setting a single DNS server with address 2001:db8:1::3.

"Dhcp6": {
    "subnet6": [
        {
            "option-data": [
                {
                    "name": "dns-servers",
                    "code": 23,
                    "space": "dhcp6",
                    "csv-format": true,
                    "data": "2001:db8:1::3"
                },
                ...
            ],
            ...
        },
        ...
    ],
    ...
}

The currently supported standard DHCPv6 options are listed in Table 8.1, “List of Standard DHCPv6 Optionsâ€. The "Name" and "Code" are the values that should be used as a name in the option-data structures. "Type" designates the format of the data: the meanings of the various types is given in Table 7.3, “List of standard DHCP option typesâ€.

Experimental options (like standard options but with a code which was not assigned by IANA) are listed in Table 8.2, “List of Experimental DHCPv6 Optionsâ€.

Some options are designated as arrays, which means that more than one value is allowed in such an option. For example the option dns-servers allows the specification of more than one IPv6 address, allowing clients to obtain the addresses of multiple DNS servers.

The Section 8.2.10, “Custom DHCPv6 Options†describes the configuration syntax to create custom option definitions (formats). It is generally not allowed to create custom definitions for standard options, even if the definition being created matches the actual option format defined in the RFCs. There is an exception from this rule for standard options for which Kea does not yes provide a definition. In order to use such options, a server administrator must create a definition as described in Section 8.2.10, “Custom DHCPv6 Options†in the 'dhcp6' option space. This definition should match the option format described in the relevant RFC but the configuration mechanism would allow any option format as it has no means to validate the format at the moment.

Table 8.1. List of Standard DHCPv6 Options

NameCodeTypeArray?
preference7uint8false
unicast12ipv6-addressfalse
vendor-opts17uint32false
sip-server-dns21fqdntrue
sip-server-addr22ipv6-addresstrue
dns-servers23ipv6-addresstrue
domain-search24fqdntrue
nis-servers27ipv6-addresstrue
nisp-servers28ipv6-addresstrue
nis-domain-name29fqdntrue
nisp-domain-name30fqdntrue
sntp-servers31ipv6-addresstrue
information-refresh-time32uint32false
bcmcs-server-dns33fqdntrue
bcmcs-server-addr34ipv6-addresstrue
geoconf-civic36record (uint8, uint16, binary)false
remote-id37record (uint32, binary)false
subscriber-id38binaryfalse
client-fqdn39record (uint8, fqdn)false
pana-agent40ipv6-addresstrue
new-posix-timezone41stringfalse
new-tzdb-timezone42stringfalse
ero43uint16true
lq-query44record (uint8, ipv6-address)false
client-data45emptyfalse
clt-time46uint32false
lq-relay-data47record (ipv6-address, binary)false
lq-client-link48ipv6-addresstrue
bootfile-url59stringfalse
bootfile-param60binaryfalse
client-arch-type61uint16true
nii62record (uint8, uint8, uint8)false
erp-local-domain-name65fqdnfalse
rsoo66emptyfalse
client-linklayer-addr79binaryfalse
dhcp4o6-server-addr88ipv6-addresstrue


Table 8.2. List of Experimental DHCPv6 Options

NameCodeTypeArray?
public-key701binaryfalse
certificate702binaryfalse
signature703record (uint8, uint8, binary)false
timestamp704binaryfalse


8.2.10. Custom DHCPv6 Options

It is possible to define options in addition to the standard ones. Assume that we want to define a new DHCPv6 option called "foo" which will have code 100 and which will convey a single unsigned 32 bit integer value. We can define such an option by using the following commands:

"Dhcp6": {
    "option-def": [
        {
            "name": "foo",
            "code": 100,
            "type": "uint32",
            "array": false,
            "record-types": "",
            "space": "dhcp6",
            "encapsulate": ""
        }, ...
    ],
    ...
}

The "false" value of the array parameter determines that the option does NOT comprise an array of "uint32" values but rather a single value. Two other parameters have been left blank: record-types and encapsulate. The former specifies the comma separated list of option data fields if the option comprises a record of data fields. The record-types value should be non-empty if the type is set to "record". Otherwise it must be left blank. The latter parameter specifies the name of the option space being encapsulated by the particular option. If the particular option does not encapsulate any option space it should be left blank. Note that the above example only defines the format of the new option, it does not set its value(s).

The name, code and type parameters are required, all others are optional. The array default value is false. The record-types and encapsulate default values are blank (i.e. ""). The default space is "dhcp6".

Once the new option format is defined, its value is set in the same way as for a standard option. For example the following commands set a global value that applies to all subnets.

"Dhcp6": {
    "option-data": [
        {
            "name": "foo",
            "code": 100,
            "space": "dhcp6",
            "csv-format": true,
            "data": "12345"
        }, ...
    ],
    ...
}

New options can take more complex forms than simple use of primitives (uint8, string, ipv6-address etc): it is possible to define an option comprising a number of existing primitives.

For example, assume we want to define a new option that will consist of an IPv6 address, followed by an unsigned 16 bit integer, followed by a boolean value, followed by a text string. Such an option could be defined in the following way:

"Dhcp6": {
    "option-def": [
        {
            "name": "bar",
            "code": 101,
            "space": "dhcp6",
            "type": "record",
            "array": false,
            "record-types": "ipv6-address, uint16, boolean, string",
            "encapsulate": ""
        }, ...
    ],
    ...
}

The "type" is set to "record" to indicate that the option contains multiple values of different types. These types are given as a comma-separated list in the "record-types" field and should be those listed in Table 7.3, “List of standard DHCP option typesâ€.

The values of the option are set as follows:

"Dhcp6": {
    "option-data": [
        {
            "name": "bar",
            "space": "dhcp6",
            "code": 101,
            "csv-format": true,
            "data": "2001:db8:1::10, 123, false, Hello World"
        }
    ],
    ...
}

csv-format is set true to indicate that the data field comprises a command-separated list of values. The values in the "data" must correspond to the types set in the "record-types" field of the option definition.

Note

In the general case, boolean values are specified as true or false, without quotes. Some specific boolean parameters may accept also "true", "false", 0, 1, "0" and "1". Future versions of Kea will accept all those values for all boolean parameters.

8.2.11. DHCPv6 Vendor-Specific Options

Currently there are two option spaces defined for the DHCPv6 daemon: "dhcp6" (for top level DHCPv6 options) and "vendor-opts-space", which is empty by default, but in which options can be defined. Those options will be carried in the Vendor-Specific Information option (code 17). The following examples show how to define an option "foo" with code 1 that consists of an IPv6 address, an unsigned 16 bit integer and a string. The "foo" option is conveyed in a Vendor-Specific Information option. This option comprises a single uint32 value that is set to "12345". The sub-option "foo" follows the data field holding this value.

"Dhcp6": {
    "option-def": [
        {
            "name": "foo",
            "code": 1,
            "space": "vendor-opts-space",
            "type": "record",
            "array": false,
            "record-types": "ipv6-address, uint16, string",
            "encapsulate": ""
        }
    ],
    ...
}

(Note that the option space is set to vendor-opts-space.) Once the option format is defined, the next step is to define actual values for that option:

"Dhcp6": {
    "option-data": [
        {
            "name": "foo",
            "space": "vendor-opts-space",
            "data": "2001:db8:1::10, 123, Hello World"
        },
        ...
    ],
    ...
}

We should also define a value (enterprise-number) for the Vendor-specific Information option, that conveys our option "foo".

"Dhcp6": {
    "option-data": [
        ...,
        {
            "name": "vendor-opts",
            "data": "12345"
        }
    ],
    ...
}

Alternatively, the option can be specified using its code.

"Dhcp6": {
    "option-data": [
        ...,
        {
            "code": 17,
            "data": "12345"
        }
    ],
    ...
}

8.2.12. Nested DHCPv6 Options (Custom Option Spaces)

It is sometimes useful to define completely new option spaces. This is useful if the user wants their new option to convey sub-options that use a separate numbering scheme, for example sub-options with codes 1 and 2. Those option codes conflict with standard DHCPv6 options, so a separate option space must be defined.

Note that it is not required to create a new option space when defining sub-options for a standard option because it is created by default if the standard option is meant to convey any sub-options (see Section 8.2.11, “DHCPv6 Vendor-Specific Optionsâ€).

Assume that we want to have a DHCPv6 option called "container" with code 102 that conveys two sub-options with codes 1 and 2. First we need to define the new sub-options:

"Dhcp6": {
    "option-def": [
        {
            "name": "subopt1",
            "code": 1,
            "space": "isc",
            "type": "ipv6-address",
            "record-types": "",
            "array": false,
            "encapsulate": ""
        },
        {
            "name": "subopt2",
            "code": 2,
            "space": "isc",
            "type": "string",
            "record-types": "",
            "array": false
            "encapsulate": ""
        }
    ],
    ...
}

Note that we have defined the options to belong to a new option space (in this case, "isc").

The next step is to define a regular DHCPv6 option and specify that it should include options from the isc option space:

"Dhcp6": {
    "option-def": [
        ...,
        {
            "name": "container",
            "code": 102,
            "space": "dhcp6",
            "type": "empty",
            "array": false,
            "record-types": "",
            "encapsulate": "isc"
        }
    ],
    ...
}

The name of the option space in which the sub-options are defined is set in the encapsulate field. The type field is set to empty which limits this option to only carrying data in sub-options.

Finally, we can set values for the new options:

"Dhcp6": {
    "option-data": [
        {
            "name": "subopt1",
            "code": 1,
            "space": "isc",
            "data": "2001:db8::abcd"
        },
        }
            "name": "subopt2",
            "code": 2,
            "space": "isc",
            "data": "Hello world"
        },
        {
            "name": "container",
            "code": 102,
            "space": "dhcp6"
        }
    ],
    ...
}

Note that it is possible to create an option which carries some data in addition to the sub-options defined in the encapsulated option space. For example, if the "container" option from the previous example was required to carry an uint16 value as well as the sub-options, the "type" value would have to be set to "uint16" in the option definition. (Such an option would then have the following data structure: DHCP header, uint16 value, sub-options.) The value specified with the "data" parameter — which should be a valid integer enclosed in quotes, e.g. "123" — would then be assigned to the uint16 field in the "container" option.

8.2.13. Unspecified Parameters for DHCPv6 Option Configuration

In many cases it is not required to specify all parameters for an option configuration and the default values can be used. However, it is important to understand the implications of not specifying some of them as it may result in configuration errors. The list below explains the behavior of the server when a particular parameter is not explicitly specified:

  • name - the server requires an option name or option code to identify an option. If this parameter is unspecified, the option code must be specified.
  • code - the server requires an option name or option code to identify an option. This parameter may be left unspecified if the name parameter is specified. However, this also requires that the particular option has its definition (it is either a standard option or an administrator created a definition for the option using an 'option-def' structure), as the option definition associates an option with a particular name. It is possible to configure an option for which there is no definition (unspecified option format). Configuration of such options requires the use of option code.
  • space - if the option space is unspecified it will default to 'dhcp6' which is an option space holding DHCPv6 standard options.
  • data - if the option data is unspecified it defaults to an empty value. The empty value is mostly used for the options which have no payload (boolean options), but it is legal to specify empty values for some options which carry variable length data and which spec allows for the length of 0. For such options, the data parameter may be omitted in the configuration.
  • csv-format - if this value is not specified and the definition for the particular option exists, the server will assume that the option data is specified as a list of comma separated values to be assigned to individual fields of the DHCP option. If the definition does not exist for this option, the server will assume that the data parameter contains the option payload in the binary format (represented as a string of hexadecimal digits). Note that not specifying this parameter doesn't imply that it defaults to a fixed value, but the configuration data interpretation also depends on the presence of the option definition. An administrator must be aware if the definition for the particular option exists when this parameter is not specified. It is generally recommended to not specify this parameter only for the options for which the definition exists, e.g. standard options. Setting csv-format to an explicit value will cause the server to strictly check the format of the option data specified.

8.2.14. IPv6 Subnet Selection

The DHCPv6 server may receive requests from local (connected to the same subnet as the server) and remote (connecting via relays) clients. As the server may have many subnet configurations defined, it must select an appropriate subnet for a given request.

The server can not assume which of the configured subnets are local. In IPv4 it is possible as there is a reasonable expectation that the server will have a (global) IPv4 address configured on the interface, and can use that information to detect whether a subnet is local or not. That assumption is not true in IPv6: the DHCPv6 server must be able to operate while only using link-local addresses. Therefore an optional interface parameter is available within a subnet definition to designate that a given subnet is local, i.e. reachable directly over the specified interface. For example the server that is intended to serve a local subnet over eth0 may be configured as follows:

"Dhcp6": {
    "subnet6": [
        {
            "subnet": "2001:db8:beef::/48",
            "pools": [
                 {
                     "pool": "2001:db8:beef::/48"
                 }
             ],
            "interface": "eth0"
        }
    ],
    ...
}

8.2.15. Rapid Commit

The Rapid Commit option, described in RFC 3315, is supported by the Kea DHCPv6 server. However, support is disabled by default for all subnets. It can be enabled for a particular subnet using the rapid-commit parameter as shown below:

"Dhcp6": {
    "subnet6": [
        {
            "subnet": "2001:db8:beef::/48",
            "rapid-commit": true,
            "pools": [
                 {
                     "pool": "2001:db8:beef::1-2001:db8:beef::10"
                 }
             ],
        }
    ],
    ...
}

This setting only affects the subnet for which the rapid-commit is set to true. For clients connected to other subnets, the server will ignore the Rapid Commit option sent by the client and will follow the 4-way exchange procedure, i.e. respond with an Advertise for a Solicit containing a Rapid Commit option.

8.2.16. DHCPv6 Relays

A DHCPv6 server with multiple subnets defined must select the appropriate subnet when it receives a request from a client. For clients connected via relays, two mechanisms are used:

The first uses the linkaddr field in the RELAY_FORW message. The name of this field is somewhat misleading in that it does not contain a link-layer address: instead, it holds an address (typically a global address) that is used to identify a link. The DHCPv6 server checks if the address belongs to a defined subnet and, if it does, that subnet is selected for the client's request.

The second mechanism is based on interface-id options. While forwarding a client's message, relays may insert an interface-id option into the message that identifies the interface on the relay that received the message. (Some relays allow configuration of that parameter, but it is sometimes hardcoded and may range from the very simple (e.g. "vlan100") to the very cryptic: one example seen on real hardware was "ISAM144|299|ipv6|nt:vp:1:110"). The server can use this information to select the appropriate subnet. The information is also returned to the relay which then knows the interface to use to transmit the response to the client. In order for this to work successfully, the relay interface IDs must be unique within the network and the server configuration must match those values.

When configuring the DHCPv6 server, it should be noted that two similarly-named parameters can be configured for a subnet:

  • interface defines which local network interface can be used to access a given subnet.
  • interface-id specifies the content of the interface-id option used by relays to identify the interface on the relay to which the response packet is sent.

The two are mutually exclusive: a subnet cannot be both reachable locally (direct traffic) and via relays (remote traffic). Specifying both is a configuration error and the DHCPv6 server will refuse such a configuration.

The following example configuration shows how to specify an interface-id with a value of "vlan123".

"Dhcp6": {
    "subnet6": [
        {
            "subnet": "2001:db8:beef::/48",
            "pools": [
                 {
                     "pool": "2001:db8:beef::/48"
                 }
             ],
            "interface-id": "vlan123"
        }
    ],
    ...
}

8.2.17. Relay-Supplied Options

RFC 6422 defines a mechanism called Relay-Supplied DHCP Options. In certain cases relay agents are the only entities that may have specific information. They can insert options when relaying messages from the client to the server. The server will then do certain checks and copy those options to the response that will be sent to the client.

There are certain conditions that must be met for the option to be included. First, the server must not provide the option itself. In other words, if both relay and server provide an option, the server always takes precedence. Second, the option must be RSOO-enabled. IANA maintains a list of RSOO-enabled options here. However, there may be cases when system administrators want to echo other options. Kea can be instructed to treat other options as RSOO-enabled. For example, to mark options 110, 120 and 130 as RSOO-enabled, the following syntax should be used:

"Dhcp6": {
    "relay-supplied-options": [ "110", "120", "130" ],
    ...
}

As of March 2015, only option 65 is RSOO-enabled by IANA. This option will always be treated as such and there's no need to explicitly mark it. Also, when enabling standard options, it is possible to use their names, rather than option code, e.g. (e.g. use dns-servers instead of 23). See Table 8.1, “List of Standard DHCPv6 Options†for the names. In certain cases it could also work for custom options, but due to the nature of the parser code this may be unreliable and should be avoided.

8.2.18. Client Classification in DHCPv6

The DHCPv6 server includes support for client classification. For a deeper discussion of the classification process see Chapter 12, Client Classification.

In certain cases it is useful to differentiate between different types of clients and treat them accordingly. It is envisaged that client classification will be used for changing the behavior of almost any part of the DHCP message processing, including the assignment of leases from different pools, the assignment of different options (or different values of the same options) etc. In the current release of the software however, there are only two mechanisms that take advantage of client classification: subnet selection and assignment of different options.

Kea can be instructed to limit access to given subnets based on class information. This is particularly useful for cases where two types of devices share the same link and are expected to be served from two different subnets. The primary use case for such a scenario is cable networks. Here, there are two classes of devices: the cable modem itself, which should be handed a lease from subnet A and all other devices behind the modem that should get a lease from subnet B. That segregation is essential to prevent overly curious users from playing with their cable modems. For details on how to set up class restrictions on subnets, see Section 12.6, “Configuring Subnets With Class Informationâ€.

The process of doing classification is conducted in three steps. The first step is to assess an incoming packet and assign it to zero or more classes. The second step is to choose a subnet, possibly based on the class information. The third step is to assign options again possibly based on the class information.

There are two methods of doing classification. The first is automatic and relies on examining the values in the vendor class options. Information from these options is extracted and a class name is constructed from it and added to the class list for the packet. The second allows you to specify an expression that is evaluated for each packet. If the result is true the packet is a member of the class.

Note

Care should be taken with client classification as it is easy for clients that do not meet class criteria to be denied any service altogether.

8.2.18.1. Defining and Using Custom Classes

The following example shows how to configure a class using an expression and a subnet making use of that class. This configuration defines the class named "Client_enterprise". It is comprised of all clients whose client identifiers start with the given hex string (which would indicate a DUID based on an enterprise id of 0xAABBCCDD). They will be given an address from 2001:db8:1::0 to 2001:db8:1::FFFF and the addresses of their DNS servers set to 2001:db8:0::1 and 2001:db8:2::1.

"Dhcp6": {
    "client-classes": [
        {
            "name": "Client_enterprise",
            "test": "substring(option[1].hex,0,6) == 0x0002AABBCCDD'",
            "option-data": [
                {
                    "name": "dns-servers",
                    "code": 23,
                    "space": "dhcp6",
                    "csv-format": true,
                    "data": "2001:db8:0::1, 2001:db8:2::1"
                }
            ]
        },
        ...
    ],
    "subnet6": [
        {
            "subnet": "2001:db8:1::/64",
            "pools": [ { "pool": "2001:db8:1::-2001:db8:1::ffff" } ],
            "client-class": "Client_enterprise"
        }
    ],
    ...
}

This example shows a configuration using an automatically generated "VENDOR_CLASS_" class. The Administrator of the network has decided that addresses from range 2001:db8:1::1 to 2001:db8:1::ffff are going to be managed by the Dhcp6 server and only clients belonging to the eRouter1.0 client class are allowed to use that pool.

"Dhcp6": {
    "subnet6": [
        {
            "subnet": "2001:db8:1::/64",
            "pools": [
                 {
                     "pool": "2001:db8:1::-2001:db8:1::ffff"
                 }
             ],
            "client-class": "VENDOR_CLASS_eRouter1.0"
        }
    ],
    ...
}

8.2.19. DDNS for DHCPv6

As mentioned earlier, kea-dhcp6 can be configured to generate requests to the DHCP-DDNS server (referred to here as "D2") to update DNS entries. These requests are known as NameChangeRequests or NCRs. Each NCR contains the following information:

  1. Whether it is a request to add (update) or remove DNS entries

  2. Whether the change requests forward DNS updates (AAAA records), reverse DNS updates (PTR records), or both.

  3. The FQDN, lease address, and DHCID

The parameters controlling the generation of NCRs for submission to D2 are contained in the dhcp-ddns section of the kea-dhcp6 configuration. The mandatory parameters for the DHCP DDNS configuration are enable-updates which is unconditionally required, and qualifying-suffix which has no default value and is required when enable-updates is set to true. The two (disabled and enabled) minimal DHCP DDNS configurations are:

"Dhcp6": {
    "dhcp-ddns": {
        "enable-updates": false
    },
    ...
}

and for example:

"Dhcp6": {
    "dhcp-ddns": {
        "enable-updates": true,
        "qualifying-suffix": "example."
    },
    ...
}

The default values for the "dhcp-ddns" section are as follows:

  • "server-ip": "127.0.0.1"
  • "server-port": 53001
  • "sender-ip": ""
  • "sender-port": 0
  • "max-queue-size": 1024
  • "ncr-protocol": "UDP"
  • "ncr-format": "JSON"
  • "override-no-update": false
  • "override-client-update": false
  • "replace-client-name": "never"
  • "generated-prefix": "myhost"

8.2.19.1. DHCP-DDNS Server Connectivity

In order for NCRs to reach the D2 server, kea-dhcp6 must be able to communicate with it. kea-dhcp6 uses the following configuration parameters to control this communication:

  • enable-updates - determines whether or not kea-dhcp6 will generate NCRs. If missing, this value is assumed to be false hence DDNS updates are disabled. To enable DDNS updates set this value to true:
  • server-ip - IP address on which D2 listens for requests. The default is the local loopback interface at address 127.0.0.1. You may specify either an IPv4 or IPv6 address.
  • server-port - port on which D2 listens for requests. The default value is 53001.
  • sender-ip - IP address which kea-dhcp6 should use to send requests to D2. The default value is blank which instructs kea-dhcp6 to select a suitable address.
  • sender-port - port which kea-dhcp6 should use to send requests to D2. The default value of 0 instructs kea-dhcp6 to select a suitable port.
  • max-queue-size - maximum number of requests allowed to queue waiting to be sent to D2. This value guards against requests accumulating uncontrollably if they are being generated faster than they can be delivered. If the number of requests queued for transmission reaches this value, DDNS updating will be turned off until the queue backlog has been sufficiently reduced. The intent is to allow kea-dhcp6 to continue lease operations. The default value is 1024.
  • ncr-protocol - socket protocol use when sending requests to D2. Currently only UDP is supported. TCP may be available in an upcoming release.
  • ncr-format - packet format to use when sending requests to D2. Currently only JSON format is supported. Other formats may be available in future releases.

By default, kea-dhcp-ddns is assumed to running on the same machine as kea-dhcp6, and all of the default values mentioned above should be sufficient. If, however, D2 has been configured to listen on a different address or port, these values must altered accordingly. For example, if D2 has been configured to listen on 2001:db8::5 port 900, the following configuration would be required:

"Dhcp6": {
    "dhcp-ddns": {
        "server-ip": "2001:db8::5",
        "server-port": 900,
        ...
    },
    ...
}

8.2.19.2. When Does kea-dhcp6 Generate a DDNS Request?

kea-dhcp6 follows the behavior prescribed for DHCP servers in RFC 4704. It is important to keep in mind that kea-dhcp6 provides the initial decision making of when and what to update and forwards that information to D2 in the form of NCRs. Carrying out the actual DNS updates and dealing with such things as conflict resolution are within the purview of D2 itself (Chapter 10, The DHCP-DDNS Server). This section describes when kea-dhcp6 will generate NCRs and the configuration parameters that can be used to influence this decision. It assumes that the enable-updates parameter is true.

Note

Currently the interface between kea-dhcp6 and D2 only supports requests which update DNS entries for a single IP address. If a lease grants more than one address, kea-dhcp6 will create the DDNS update request for only the first of these addresses. Support for multiple address mappings may be provided in a future release.

In general, kea-dhcp6 will generate DDNS update requests when:

  1. A new lease is granted in response to a REQUEST

  2. An existing lease is renewed but the FQDN associated with it has changed.

  3. An existing lease is released in response to a RELEASE

In the second case, lease renewal, two DDNS requests will be issued: one request to remove entries for the previous FQDN and a second request to add entries for the new FQDN. In the last case, a lease release, a single DDNS request to remove its entries will be made.

The decision making involved when granting a new lease the first case) is more involved. When a new lease is granted, kea-dhcp6 will generate a DDNS update request only if the REQUEST contains the FQDN option (code 39). By default kea-dhcp6 will respect the FQDN N and S flags specified by the client as shown in the following table:

Table 8.3. Default FQDN Flag Behavior

Client Flags:N-SClient IntentServer ResponseServer Flags:N-S-O
0-0 Client wants to do forward updates, server should do reverse updates Server generates reverse-only request1-0-0
0-1Server should do both forward and reverse updatesServer generates request to update both directions0-1-0
1-0Client wants no updates doneServer does not generate a request1-0-0

The first row in the table above represents "client delegation". Here the DHCP client states that it intends to do the forward DNS updates and the server should do the reverse updates. By default, kea-dhcp6 will honor the client's wishes and generate a DDNS request to D2 to update only reverse DNS data. The parameter, override-client-update, can be used to instruct the server to override client delegation requests. When this parameter is true, kea-dhcp6 will disregard requests for client delegation and generate a DDNS request to update both forward and reverse DNS data. In this case, the N-S-O flags in the server's response to the client will be 0-1-1 respectively.

(Note that the flag combination N=1, S=1 is prohibited according to RFC 4702. If such a combination is received from the client, the packet will be dropped by kea-dhcp6.)

To override client delegation, set the following values in the configuration:

"Dhcp6": {
    "dhcp-ddns": {
        "override-client-update": true,
        ...
    },
    ...
}

The third row in the table above describes the case in which the client requests that no DNS updates be done. The parameter, override-no-update, can be used to instruct the server to disregard the client's wishes. When this parameter is true, kea-dhcp6 will generate DDNS update requests to kea-dhcp-ddns even if the client requests no updates be done. The N-S-O flags in the server's response to the client will be 0-1-1.

To override client delegation, issue the following commands:

"Dhcp6": {
    "dhcp-ddns": {
        "override-no-update": true,
        ...
    },
    ...
}

8.2.19.3. kea-dhcp6 Name Generation for DDNS Update Requests

Each NameChangeRequest must of course include the fully qualified domain name whose DNS entries are to be affected. kea-dhcp6 can be configured to supply a portion or all of that name based upon what it receives from the client.

The default rules for constructing the FQDN that will be used for DNS entries are:

  1. If the DHCPREQUEST contains the client FQDN option, the candidate name is taken from there.

  2. If the candidate name is a partial (i.e. unqualified) name then add a configurable suffix to the name and use the result as the FQDN.

  3. If the candidate name provided is empty, generate an FQDN using a configurable prefix and suffix.

  4. If the client provided neither option, then no DNS action will be taken.

These rules can amended by setting the replace-client-name parameter which provides the following modes of behavior:

  • never - Use the name the client sent. If the client sent no name, do not generate one. This is the default mode.

  • always - Replace the name the client sent. If the client sent no name, generate one for the client.

  • when-present - Replace the name the client sent. If the client sent no name, do not generate one.

  • when-not-present - Use the name the client sent. If the client sent no name, generate one for the client.

Note

Note that formerly, this parameter was a boolean and permitted only values of true and false. Boolean values will still be accepted but may eventually be deprecated. A value of true equates to when-present, false equates to never.

For example, To instruct kea-dhcp6 to always generate the FQDN for a client, set the parameter replace-client-name to always as follows:

"Dhcp6": {
    "dhcp-ddns": {
        "replace-client-name": "always",
        ...
    },
    ...
}

The prefix used in the generation of an FQDN is specified by the generated-prefix parameter. The default value is "myhost". To alter its value, simply set it to the desired string:

"Dhcp6": {
    "dhcp-ddns": {
        "generated-prefix": "another.host",
        ...
    },
    ...
}

The suffix used when generating an FQDN or when qualifying a partial name is specified by the qualifying-suffix parameter. This parameter has no default value, thus it is mandatory when DDNS updates are enabled. To set its value simply set it to the desired string:

"Dhcp6": {
    "dhcp-ddns": {
        "qualifying-suffix": "foo.example.org",
        ...
    },
    ...
}

When qualifying a partial name, kea-dhcp6 will construct a name with the format:

[candidate-name].[qualifying-suffix].

where candidate-name is the partial name supplied in the REQUEST. For example, if FQDN domain name value was "some-computer" and qualifying-suffix "example.com", the generated FQDN would be:

some-computer.example.com.

When generating the entire name, kea-dhcp6 will construct name of the format:

[generated-prefix]-[address-text].[qualifying-suffix].

where address-text is simply the lease IP address converted to a hyphenated string. For example, if lease address is 3001:1::70E, the qualifying suffix "example.com", and the default value is used for generated-prefix, the generated FQDN would be:

myhost-3001-1--70E.example.com.

8.2.20. DHCPv4-over-DHCPv6: DHCPv6 Side

The support of DHCPv4-over-DHCPv6 transport is described in RFC 7341 and is implemented using cooperating DHCPv4 and DHCPv6 servers. This section is about the configuration of the DHCPv6 side (the DHCPv4 side is described in Section 7.2.19, “DHCPv4-over-DHCPv6: DHCPv4 Sideâ€).

Note

DHCPv4-over-DHCPv6 support is experimental and the details of the inter-process communication can change: both the DHCPv4 and DHCPv6 sides should be running the same version of Kea.

There is only one specific parameter for the DHCPv6 side: dhcp4o6-port which specifies the first of the two consecutive ports of the UDP sockets used for the communication between the DHCPv6 and DHCPv4 servers (the DHCPv6 server is bound to ::1 on port and connected to ::1 on port + 1).

Two other configuration entries are in general required: unicast traffic support (see Section 8.2.6, “Unicast Traffic Supportâ€) and DHCP 4o6 server address option (name "dhcp4o6-server-addr", code 88).

The following configuration was used during some tests:

{

# DHCPv6 conf
"Dhcp6": {

    "interfaces-config": {
        "interfaces": [ "eno33554984/2001:db8:1:1::1" ]
    },

    "lease-database": {
        "type": "memfile",
        "name": "leases6"
    },

    "preferred-lifetime": 3000,
    "valid-lifetime": 4000,
    "renew-timer": 1000,
    "rebind-timer": 2000,

    "subnet6": [ {
        "subnet": "2001:db8:1:1::/64",
        "interface": "eno33554984",
        "pools": [ { "pool": "2001:db8:1:1::1:0/112" } ]
    } ],

    "dhcp4o6-port": 6767,

    "option-data": [ {
        "name": "dhcp4o6-server-addr",
        "code": 88,
        "space": "dhcp6",
        "csv-format": true,
        "data": "2001:db8:1:1::1"
    } ]

},

"Logging": {
    "loggers": [ {
        "name": "kea-dhcp6",
        "output_options": [ {
            "output": "/tmp/kea-dhcp6.log"
        } ],
        "severity": "DEBUG",
        "debuglevel": 0
    } ]
}

}

Note

Relayed DHCPv4-QUERY DHCPv6 messages are not yet supported.

8.3. Host Reservation in DHCPv6

There are many cases where it is useful to provide a configuration on a per host basis. The most obvious one is to reserve specific, static IPv6 address or/and prefix for exclusive use by a given client (host) †returning client will get the same address or/and prefix every time and other clients will never get that address. Note that there may be cases when the new reservation has been made for the client for the address or prefix being currently in use by another client. We call this situation a "conflict". The conflicts get resolved automatically over time as described in the subsequent sections. Once conflict is resolved, the client will keep receiving the reserved configuration when it renews.

Another example when the host reservations are applicable is when a host has specific requirements, e.g. a printer that needs additional DHCP options or a cable modem needs specific parameters. Yet another possible use case for host reservation is to define unique names for hosts.

Hosts reservations are defined as parameters for each subnet. Each host can be identified by either DUID or its hardware/MAC address. See Section 8.9, “MAC/Hardware Addresses in DHCPv6†for details. There is an optional reservations array in the subnet6 structure. Each element in that array is a structure, that holds information about a single host. In particular, the structure has an identifier that uniquely identifies a host. In the DHCPv6 context, such an identifier is usually a DUID, but can also be a hardware or MAC address. Also, either one or more addresses or prefixes may be specified. It is possible to specify a hostname and DHCPv6 options for a given host.

The following example shows how to reserve addresses and prefixes for specific hosts:

"subnet6": [
    {
        "subnet": "2001:db8:1::/48",
        "pools": [ { "pool": "2001:db8:1::/80" } ],
        "pd-pools": [
            {
                "prefix": "2001:db8:1:8000::",
                "prefix-len": 56,
                "delegated-len": 64
            }
        ],
        "reservations": [
            {
                "duid": "01:02:03:04:05:0A:0B:0C:0D:0E",
                "ip-addresses": [ "2001:db8:1::100" ]
            },
            {
                "hw-address": "00:01:02:03:04:05",
                "ip-addresses": [ "2001:db8:1::101, 2001:db8:1::102" ]
            },
            {
                "duid": "01:02:03:04:05:06:07:08:09:0A",
                "ip-addresses": [ "2001:db8:1::103" ],
                "prefixes": [ "2001:db8:2:abcd::/64" ],
                "hostname": "foo.example.com"
            }
        ]
    }
]

This example includes reservations for three different clients. The first reservation is made for the address 2001:db8:1::100 for a client using DUID 01:02:03:04:05:0A:0B:0C:0D:0E. The second reservation is made for two addresses 2001:db8:1::101 and 2001:db8:1::102 for a client using MAC address 00:01:02:03:04:05. Lastly, address 2001:db8:1::103 and prefix 2001:db8:2:abcd::/64 are reserved for a client using DUID 01:02:03:04:05:06:07:08:09:0A. The last reservation also assigns a hostname to this client.

Note that DHCPv6 allows for a single client to lease multiple addresses and multiple prefixes at the same time. Therefore ip-addresses and prefixes are plural and are actually arrays. When the client sends multiple IA options (IA_NA or IA_PD), each reserved address or prefix is assigned to an individual IA of the appropriate type. If the number of IAs of specific type is lower than the number of reservations of that type, the number of reserved addresses or prefixes assigned to the client is equal to the number of IA_NAs or IA_PDs sent by the client, i.e. some reserved addresses or prefixes are not assigned. However, they still remain reserved for this client and the server will not assign them to any other client. If the number of IAs of specific type sent by the client is greater than the number of reserved addresses or prefixes, the server will try to assign all reserved addresses or prefixes to the individual IAs and dynamically allocate addresses or prefixes to remaining IAs. If the server cannot assign a reserved address or prefix because it is in use, the server will select the next reserved address or prefix and try to assign it to the client. If the server subsequently finds that there are no more reservations that can be assigned to the client at the moment, the server will try to assign leases dynamically.

Making a reservation for a mobile host that may visit multiple subnets requires a separate host definition in each subnet it is expected to visit. It is not allowed to define multiple host definitions with the same hardware address in a single subnet. Multiple host definitions with the same hardware address are valid if each is in a different subnet. The reservation for a given host should include only one identifier, either DUID or hardware address. Defining both for the same host is considered a configuration error, but as of 1.1.0, it is not rejected.

Adding host reservation incurs a performance penalty. In principle, when a server that does not support host reservation responds to a query, it needs to check whether there is a lease for a given address being considered for allocation or renewal. The server that also supports host reservation, has to perform additional checks: not only if the address is currently used (i.e. if there is a lease for it), but also whether the address could be used by someone else (i.e. if there is a reservation for it). That additional check incurs additional overhead.

8.3.1. Address/Prefix Reservation Types

In a typical scenario there is an IPv6 subnet defined with a certain part of it dedicated for dynamic address allocation by the DHCPv6 server. There may be an additional address space defined for prefix delegation. Those dynamic parts are referred to as dynamic pools, address and prefix pools or simply pools. In principle, the host reservation can reserve any address or prefix that belongs to the subnet. The reservations that specify an address that belongs to configured pools are called "in-pool reservations". In contrast, those that do not belong to dynamic pools are called "out-of-pool reservations". There is no formal difference in the reservation syntax and both reservation types are handled uniformly. However, upcoming releases may offer improved performance if there are only out-of-pool reservations as the server will be able to skip reservation checks when dealing with existing leases. Therefore, system administrators are encouraged to use out-of-pool reservations if possible.

8.3.2. Conflicts in DHCPv6 Reservations

As reservations and lease information are stored separately, conflicts may arise. Consider the following series of events. The server has configured the dynamic pool of addresses from the range of 2001:db8::10 to 2001:db8::20. Host A requests an address and gets 2001:db8::10. Now the system administrator decides to reserve address 2001:db8::10 for Host B. In general, reserving an address that is currently assigned to someone else is not recommended, but there are valid use cases where such an operation is warranted.

The server now has a conflict to resolve. Let's analyze the situation here. If Host B boots up and request an address, the server is not able to assign the reserved address 2001:db8::10. A naive approach would to be immediately remove the lease for Host A and create a new one for Host B. That would not solve the problem, though, because as soon as Host B get the address, it will detect that the address is already in use by someone else (Host A) and would send a Decline message. Therefore in this situation, the server has to temporarily assign a different address from the dynamic pool (not matching what has been reserved) to Host B.

When Host A renews its address, the server will discover that the address being renewed is now reserved for someone else (Host B). Therefore the server will remove the lease for 2001:db8::10, select a new address and create a new lease for it. It will send two addresses in its response: the old address with lifetime set to 0 to explicitly indicate that it is no longer valid and the new address with a non-zero lifetime. When Host B renews its temporarily assigned address, the server will detect that the existing lease does not match reservation, so it will release the current address Host B has and will create a new lease matching the reservation. Similar as before, the server will send two addresses: the temporarily assigned one with zeroed lifetimes, and the new one that matches reservation with proper lifetimes set.

This recovery will succeed, even if other hosts will attempt to get the reserved address. Had Host C requested address 2001:db8::10 after the reservation was made, the server will propose a different address.

This recovery mechanism allows the server to fully recover from a case where reservations conflict with existing leases. This procedure takes time and will roughly take as long as renew-timer value specified. The best way to avoid such recovery is to not define new reservations that conflict with existing leases. Another recommendation is to use out-of-pool reservations. If the reserved address does not belong to a pool, there is no way that other clients could get this address.

8.3.3. Reserving a Hostname

When the reservation for the client includes the hostname, the server will assign this hostname to the client and send it back in the Client FQDN, if the client sent the FQDN option to the server. The reserved hostname always takes precedence over the hostname supplied by the client (via the FQDN option) or the autogenerated (from the IPv6 address) hostname.

The server qualifies the reserved hostname with the value of the qualifying-suffix parameter. For example, the following subnet configuration:

"subnet6": [
    {
        "subnet": "2001:db8:1::/48",
        "pools": [ { "pool": "2001:db8:1::/80" } ],
        "reservations": [
            {
                "duid": "01:02:03:04:05:0A:0B:0C:0D:0E",
                "ip-addresses": [ "2001:db8:1::100" ]
                "hostname": "alice-laptop"
            }
        ]
    }
],
"dhcp-ddns": {
    "enable-updates": true,
    "qualifying-suffix": "example.isc.org."
}

will result in assigning the "alice-laptop.example.isc.org." hostname to the client using the DUID "01:02:03:04:05:0A:0B:0C:0D:0E". If the qualifying-suffix is not specified, the default (empty) value will be used, and in this case the value specified as a hostname will be treated as fully qualified name. Thus, by leaving the qualifying-suffix empty it is possible to qualify hostnames for the different clients with different domain names:

"subnet6": [
    {
        "subnet": "2001:db8:1::/48",
        "pools": [ { "pool": "2001:db8:1::/80" } ],
        "reservations": [
            {
                "duid": "01:02:03:04:05:0A:0B:0C:0D:0E",
                "ip-addresses": [ "2001:db8:1::100" ]
                "hostname": "mark-desktop.example.org."
            }
        ]
    }
],
"dhcp-ddns": {
    "enable-updates": true,
}

The above example results in the assignment of the "mark-desktop.example.org." hostname to the client using the DUID "01:02:03:04:05:0A:0B:0C:0D:0E".

8.3.4. Including Specific DHCPv6 Options in Reservations

Kea 1.1.0 introduced the ability to specify options on a per host basis. The options follow the same rules as any other options. These can be standard options (see Section 8.2.9, “Standard DHCPv6 Optionsâ€), custom options (see Section 8.2.10, “Custom DHCPv6 Optionsâ€) or vendor specific options (see Section 8.2.11, “DHCPv6 Vendor-Specific Optionsâ€). The following example demonstrates how standard options can be defined.

"reservations": [
{
   "duid": "01:02:03:05:06:07:08",
   "ip-addresses": [ "2001:db8:1::2" ],
    "option-data": [
    {
        "option-data": [ {
            "name": "dns-servers",
            "data": "3000:1::234"
        },
        {
            "name": "nis-servers",
            "data": "3000:1::234"
        }
    } ]
} ]

Vendor specific options can be reserved in a similar manner:

"reservations": [
{
    "duid": "aa:bb:cc:dd:ee:ff",
    "ip-addresses": [ "2001:db8::1" ],
    "option-data": [
    {
        "name": "vendor-opts",
        "data": 4491"
    },
    {
        "name": "tftp-servers",
        "space": "vendor-4491",
        "data": "3000:1::234"
    } ]
} ]

Options defined on host level have the highest priority. In other words, if there are options defined with the same type on global, subnet, class and host level, the host specific values will be used.

8.3.5. Reserving Client Classes in DHCPv6

The Section 12.4, “Using Expressions In Classification†explains how to configure the server to assign classes to a client based on the content of the options that this client sends to the server. Host reservations mechanisms also allow for the static assignment of classes to clients. The definitions of these classes are placed in the Kea configuration. The following configuration snippet shows how to specify that the client belongs to classes reserved-class1 and reserved-class2. Those classes are associated with specific options being sent to the clients which belong to them.

{
    "client-classes": [
    {
       "name": "reserved-class1",
       "option-data": [
       {
           "name": "dns-servers",
           "data": "2001:db8:1::50"
       }
       ]
   },
   {
       "name": "reserved-class2",
       "option-data": [
       {
           "name": "nis-servers",
           "data": "2001:db8:1::100"
       }
       ]
    }
    ],
    "subnet6": [
    {   "pools": [ { "pool": "2001:db8:1::/64" } ],
        "subnet": "2001:db8:1::/48",
        "reservations": [
        {
            "duid": "01:02:03:04:05:06:07:08",
            
            "client-classes": [ "reserved-class1", "reserved-class2" ]
            
         } ]
     } ]
 }

Static class assignments, as shown above, can be used in conjuction with classification using expressions.

8.3.6. Storing Host Reservations in MySQL or PostgreSQL

It is possible to store host reservations in MySQL or PostgreSQL. See Section 8.2.3, “Hosts Storage†for information on how to configure Kea to use reservations stored in MySQL or PostgreSQL. Kea does not provide any dedicated tools for managing reservations in a database. The Kea wiki http://kea.isc.org/wiki/HostReservationsHowTo provides detailed information and examples of how reservations can be inserted into the database.

Note

In Kea 1.1.0 maximum length of an option specified per host is arbitrarily set to 4096 bytes.

8.3.7. Storing Host Reservations in CQL (Cassandra)

Kea currently does not support storing reservations in Cassandra (CQL).

8.3.8. Fine Tuning DHCPv6 Host Reservation

The host reservation capability introduces additional restrictions for the allocation engine (the component of Kea that selects an address for a client) during lease selection and renewal. In particular, three major checks are necessary. First, when selecting a new lease, it is not sufficient for a candidate lease to not be used by another DHCP client. It also must not be reserved for another client. Second, when renewing a lease, additional check must be performed whether the address being renewed is not reserved for another client. Finally, when a host renews an address or a prefix, the server has to check whether there is a reservation for this host, so the existing (dynamically allocated) address should be revoked and the reserved one be used instead.

Some of those checks may be unnecessary in certain deployments and not performing them may improve performance. The Kea server provides the reservation-mode configuration parameter to select the types of reservations allowed for the particular subnet. Each reservation type has different constraints for the checks to be performed by the server when allocating or renewing a lease for the client. Allowed values are:

  • all - enables all host reservation types. This is the default value. This setting is the safest and the most flexible. It allows in-pool and out-of-pool reservations. As all checks are conducted, it is also the slowest.
  • out-of-pool - allows only out of pool host reservations. With this setting in place, the server may assume that all host reservations are for addresses that do not belong to the dynamic pool. Therefore it can skip the reservation checks when dealing with in-pool addresses, thus improving performance. Do not use this mode if any of your reservations use in-pool address. Caution is advised when using this setting. Kea 1.1.0 does not sanity check the reservations against reservation-mode and misconfiguration may cause problems.
  • disabled - host reservation support is disabled. As there are no reservations, the server will skip all checks. Any reservations defined will be completely ignored. As the checks are skipped, the server may operate faster in this mode.

An example configuration that disables reservation looks like follows:

"Dhcp6": {
    "subnet6": [
        {
        "subnet": "2001:db8:1::/64",
        "reservation-mode": "disabled",
        ...
        }
    ]
}

Another aspect of the host reservations are different types of identifiers. Kea 1.1.0 supports two types of identifiers in DHCPv6: hw-address and duid, but more identifier types are likely to be added in the future. This is beneficial from a usability perspective. However, there is a drawback. For each incoming packet Kea has to to extract each identifier type and then query the database to see if there is a reservation done by this particular identifier. If nothing is found, the next identifier is extracted and next query is issued. This process continues until either a reservation is found or all identifier types have been checked. Over time with an increasing number of supported identifier types, Kea would become slower and slower.

To address this problem, a parameter called host-reservation-identifiers has been introduced. It takes a list of identifier types as a parameter. Kea will check only those identifier types enumerated in host-reservation-identifiers. From a performance perspective the number of identifier types should be kept to minimum, ideally limited to one. If your deployment uses several reservation types, please enumerate them from most to least frequently used as this increases the chances of Kea finding the reservation using the fewest number of queries. An example of host reservation identifiers looks as follows:

"host-reservation-identifiers": [ "duid", "hw-address" ],
"subnet6": [
    {
        "subnet": "2001:db8:1::/64",
        ...
    }
]

If not specified, the default value is:

"host-reservation-identifiers": [ "hw-address", "duid" ]

8.4. Server Identifier in DHCPv6

The DHCPv6 protocol uses a "server identifier" (also known as a DUID) for clients to be able to discriminate between several servers present on the same link. RFC 3315 defines three DUID types: DUID-LLT, DUID-EN and DUID-LL. RFC 6355 also defines DUID-UUID. Future specifications may introduce new DUID types.

The Kea DHCPv6 server generates a server identifier once, upon the first startup, and stores it in a file. This identifier isn't modified across restarts of the server and so is a stable identifier.

Kea follows recommendation from RFC 3315 to use DUID-LLT as the default server identifier. However, we have received reports that some deployments require different DUID types, and there is a need to administratively select both DUID type and/or its contents.

The server identifier can be configured using parameters within the server-id map element in the global scope of the Kea configuration file. The following example demonstrates how to select DUID-EN as a server identifier:

"Dhcp6": {
    "server-id": {
        "type": "EN"
    },
    ...
}

Currently supported values for type parameter are: "LLT", "EN" and "LL", for DUID-LLT, DUID-EN and DUID-LL respectively.

When a new DUID type is selected the server will generate its value and replace any existing DUID in the file. The server will then use the new server identifier in all future interactions with the clients.

Note

If the new server identifier is created after some clients have obtained their leases, the clients using the old identifier will not be able to renew the leases: the server will ignore messages containing the old server identifier. Clients will continue sending Renew until they transition to the rebinding state. In this state they will start sending Rebind messages to multicast address without a server identifier. The server will respond to the Rebind messages with a new server identifier and the clients will associate the new server identifier with their leases. Although the clients will be able to keep their leases and will eventually learn the new server identifier, this will be at the cost of increased number of renewals and multicast traffic due to a need to rebind. Therefore it is recommended that modification of the server identifier type and value is avoided if the server has already assigned leases and these leases are still valid.

There are cases when an administrator needs to explicitly specify a DUID value rather than allow the server to generate it. The following example demonstrates how to explicitly set all components of a DUID-LLT.

"Dhcp6": {
    "server-id": {
        "type": "LLT",
        "htype": 8,
        "identifier": "A65DC7410F05",
        "time": 2518920166
    },
    ...
}

where:

  • htype is a 16-bit unsigned value specifying hardware type,
  • identifier is a link layer address, specified as a string of hexadecimal digits,
  • time is a 32-bit unsigned time value.

The hexadecimal representation of the DUID generated as a result of the configuration specified above will be:

 00:01:00:08:96:23:AB:E6:A6:5D:C7:41:0F:05
|type |htype|   time    |   identifier    |

It is allowed to use special value of 0 for "htype" and "time", which indicates that the server should use ANY value for these components. If the server already uses a DUID-LLT it will use the values from this DUID. If the server uses a DUID of a different type or doesn't use any DUID yet, it will generate these values. Similarly, if the "identifier" is assigned an empty string, the value of the identifier will be generated. Omitting any of these parameters is equivalent to setting them to those special values.

For example, the following configuration:

"Dhcp6": {
    "server-id": {
        "type": "LLT",
        "htype": 0,
        "identifier": "",
        "time": 2518920166
    },
    ...
}

indicates that the server should use ANY link layer address and hardware type. If the server is already using DUID-LLT it will use the link layer address and hardware type from the existing DUID. If the server is not using any DUID yet, it will use link layer address and hardware type from one of the available network interfaces. The server will use an explicit value of time. If it is different than a time value present in the currently used DUID, that value will be replaced, effectively causing modification of the current server identifier.

The following example demonstrates an explicit configuration of a DUID-EN:

"Dhcp6": {
    "server-id": {
        "type": "EN",
        "enterprise-id": 2495,
        "identifier": "87ABEF7A5BB545"
    },
    ...
}

where:

  • enterprise-id is a 32-bit unsigned value holding enterprise number,
  • identifier is a variable length identifier within DUID-EN.

The hexadecimal representation of the DUID-EN created according to the configuration above is:

 00:02:00:00:09:BF:87:AB:EF:7A:5B:B5:45
|type |  ent-id   |     identifier     |

As in the case of the DUID-LLT, special values can be used for the configuration of the DUID-EN. If enterprise-id is 0, the server will use a value from the existing DUID-EN. If the server is not using any DUID or the existing DUID has a different type, the ISC enterprise id will be used. When an empty string is used for identifier, the identifier from the existing DUID-EN will be used. If the server is not using any DUID-EN the new 6-bytes long identifier will be generated.

DUID-LL is configured in the same way as DUID-LLT with an exception that the time parameter has no effect for DUID-LL, because this DUID type only comprises a hardware type and link layer address. The following example demonstrates how to configure DUID-LL:

"Dhcp6": {
    "server-id": {
        "type": "LL",
        "htype": 8,
        "identifier": "A65DC7410F05"
    },
    ...
}

which will result in the following server identifier:

 00:03:00:08:A6:5D:C7:41:0F:05
|type |htype|   identifier    |

The server stores the generated server identifier in the following location: [kea-install-dir]/var/kea/kea-dhcp6-serverid.

In some uncommon deployments where no stable storage is available, the server should be configured not to try to store the server identifier. This choice is controlled by the value of persist boolean parameter:

"Dhcp6": {
    "server-id": {
        "type": "EN",
        "enterprise-id": 2495,
        "identifier": "87ABEF7A5BB545",
        "persist": false
    },
    ...
}

The default value of the "persist" parameter is true which configures the server to store the server identifier on a disk.

In the example above, the server is configured to not store the generated server identifier on a disk. But, if the server identifier is not modified in the configuration the same value will be used after server restart, because entire server identifier is explicitly specified in the configuration.

8.5. Stateless DHCPv6 (Information-Request Message)

Typically DHCPv6 is used to assign both addresses and options. These assignments (leases) have state that changes over time, hence their name, stateful. DHCPv6 also supports a stateless mode, where clients request configuration options only. This mode is considered lightweight from the server perspective as it does not require any state tracking; hence its name.

The Kea server supports stateless mode. Clients can send Information-Request messages and the server will send back answers with the requested options (providing the options are available in the server configuration). The server will attempt to use per-subnet options first. If that fails - for whatever reason - it will then try to provide options defined in the global scope.

Stateless and stateful mode can be used together. No special configuration directives are required to handle this. Simply use the configuration for stateful clients and the stateless clients will get just options they requested.

This usage of global options allows for an interesting case. It is possible to run a server that provides just options and no addresses or prefixes. If the options have the same value in each subnet, the configuration can define required options in the global scope and skip subnet definitions altogether. Here's a simple example of such a configuration:

"Dhcp6": {
    "interfaces-config": {
        "interfaces": [ "ethX" ]
    },
    "option-data": [ {
        "name": "dns-servers",
        "data": "2001:db8::1, 2001:db8::2"
    } ],
    "lease-database": { "type": "memfile" }
 }

This very simple configuration will provide DNS server information to all clients in the network, regardless of their location. Note the specification of the memfile lease database: this is needed as Kea requires a lease database to be specified even if it is not used.

8.6. Support for RFC 7550

The RFC 7550 introduced some changes to the DHCPv6 protocol to resolve a few issues with the coexistence of multiple stateful options in the messages sent between the clients and servers.

The typical example is when the client, such as a requesting router, requests an allocation of both addresses and prefixes when it performs the 4-way (SARR) exchange with the server. If the server is not configured to allocate any prefixes but it can allocate some addresses, it will respond with the IA_NA(s) containing allocated addresses and the IA_PD(s) containing the NoPrefixAvail status code. If the client can operate without prefixes it may transition to the 'bound' state when it sends Renew/Rebind messages to the server, according to the T1 and T2 times, to extend the lifetimes of the allocated addresses. If the client is still interested in obtaining prefixes from the server it may also include an IA_PD in the Renew/Rebind to request allocation of the prefixes. If the server still cannot allocate the prefixes, it will respond with the IA_PD(s) containing NoPrefixAvail status code. However, if the server can now allocate the prefixes it will do so, and send them in the IA_PD(s) to the client. Allocation of leases during the Renew/Rebind was not supported in the RFC 3315 and RFC 3633, and has been introduced in RFC 7550. Kea supports this new behavior and it doesn't provide any configuration mechanisms to disable it.

The following are the other behaviors specified in the RFC 7550 supported by the Kea DHCPv6 server:

  • Set T1/T2 timers to the same value for all stateful (IA_NA and IA_PD) options to facilitate renewal of all client's leases at the same time (in a single message exchange),
  • NoAddrsAvail and NoPrefixAvail status codes are placed in the IA_NA and IA_PD options in the Advertise message, rather than as the top level options.

8.7. Using Specific Relay Agent for a Subnet

The relay has to have an interface connected to the link on which the clients are being configured. Typically the relay has a global IPv6 address configured on the interface that belongs to the subnet from which the server will assign addresses. In the typical case, the server is able to use the IPv6 address inserted by the relay (in the link-addr field in RELAY-FORW message) to select the appropriate subnet.

However, that is not always the case. The relay address may not match the subnet in certain deployments. This usually means that there is more than one subnet allocated for a given link. The two most common examples where this is the case are long lasting network renumbering (where both old and new address space is still being used) and a cable network. In a cable network both cable modems and the devices behind them are physically connected to the same link, yet they use distinct addressing. In such case, the DHCPv6 server needs additional information (like the value of interface-id option or IPv6 address inserted in the link-addr field in RELAY-FORW message) to properly select an appropriate subnet.

The following example assumes that there is a subnet 2001:db8:1::/64 that is accessible via a relay that uses 3000::1 as its IPv6 address. The server will be able to select this subnet for any incoming packets that came from a relay with an address in 2001:db8:1::/64 subnet. It will also select that subnet for a relay with address 3000::1.

"Dhcp6": {
    "subnet6": [
        {
            "subnet": "2001:db8:1::/64",
            "pools": [
                 {
                     "pool": "2001:db8:1::1-2001:db8:1::ffff"
                 }
             ],
             "relay": {
                 "ip-address": "3000::1"
             }
        }
    ]
}

8.8. Segregating IPv6 Clients in a Cable Network

In certain cases, it is useful to mix relay address information, introduced in Section 8.7, “Using Specific Relay Agent for a Subnet†with client classification, explained in Chapter 12, Client Classification. One specific example is a cable network, where typically modems get addresses from a different subnet than all devices connected behind them.

Let's assume that there is one CMTS (Cable Modem Termination System) with one CM MAC (a physical link that modems are connected to). We want the modems to get addresses from the 3000::/64 subnet, while everything connected behind modems should get addresses from another subnet (2001:db8:1::/64). The CMTS that acts as a relay an uses address 3000::1. The following configuration can serve that configuration:

"Dhcp6": {
    "subnet6": [
        {
            "subnet": "3000::/64",
            "pools": [
                { "pool": "3000::2 - 3000::ffff" }
            ],
            "client-class": "VENDOR_CLASS_docsis3.0",
            "relay": {
                "ip-address": "3000::1"
            }
        },

        {
            "subnet": "2001:db8:1::/64",
            "pools": [
                 {
                     "pool": "2001:db8:1::1-2001:db8:1::ffff"
                 }
             ],
             "relay": {
                 "ip-address": "3000::1"
             }
        }
    ]
}

8.9. MAC/Hardware Addresses in DHCPv6

MAC/hardware addresses are available in DHCPv4 messages from the clients and administrators frequently use that information to perform certain tasks, like per host configuration, address reservation for specific MAC addresses and other. Unfortunately, the DHCPv6 protocol does not provide any completely reliable way to retrieve that information. To mitigate that issue a number of mechanisms have been implemented in Kea that attempt to gather it. Each of those mechanisms works in certain cases, but may fail in other cases. Whether the mechanism works or not in the particular deployment is somewhat dependent on the network topology and the technologies used.

Kea allows configuration of which of the supported methods should be used and in what order. This configuration may be considered a fine tuning of the DHCP deployment. In a typical deployment the default value of "any" is sufficient and there is no need to select specific methods. Changing the value of this parameter is the most useful in cases when an administrator wants to disable certain method, e.g. if the administrator trusts the network infrastructure more than the information provided by the clients themselves, the administrator may prefer information provided by the relays over that provided by the clients.

The configuration is controlled by the mac-sourcesparameter as follows:

"Dhcp6": {
    "mac-sources": [ "method1", "method2", "method3", ... ],

    "subnet6": [ ... ],

    ...
}

When not specified, a special value of "any" is used, which instructs the server to attempt to use all the methods in sequence and use value returned by the first one that succeeds.

Supported methods are:

  • any - Not an actual method, just a keyword that instructs Kea to try all other methods and use the first one that succeeds. This is the default operation if no mac-sources are defined.
  • raw - In principle, a DHCPv6 server could use raw sockets to receive incoming traffic and extract MAC/hardware address information. This is currently not implemented for DHCPv6 and this value has no effect.
  • duid - DHCPv6 uses DUID identifiers instead of MAC addresses. There are currently four DUID types defined, with two of them (DUID-LLT, which is the default one and DUID-LL) convey MAC address information. Although RFC 3315 forbids it, it is possible to parse those DUIDs and extract necessary information from them. This method is not completely reliable, as clients may use other DUID types, namely DUID-EN or DUID-UUID.
  • ipv6-link-local - Another possible acquisition method comes from the source IPv6 address. In typical usage, clients are sending their packets from IPv6 link-local addresses. There is a good chance that those addresses are based on EUI-64, which contains MAC address. This method is not completely reliable, as clients may use other link-local address types. In particular, privacy extensions, defined in RFC 4941, do not use MAC addresses. Also note that successful extraction requires that the address's u-bit must be set to 1 and its g-bit set to 0, indicating that it is an interface identifier as per RFC 2373, section 2.5.1.
  • client-link-addr-option - One extension defined to alleviate missing MAC issues is client link-layer address option, defined in RFC 6939. This is an option that is inserted by a relay and contains information about client's MAC address. This method requires a relay agent that supports the option and is configured to insert it. This method is useless for directly connected clients. This parameter can also be specified as rfc6939, which is an alias for client-link-addr-option.
  • remote-id - RFC 4649 defines a remote-id option that is inserted by a relay agent. Depending on the relay agent configuration, the inserted option may convey the client's MAC address information. This parameter can also be specified as rfc4649, which is an alias for remote-id.
  • subscriber-id - Another option that is somewhat similar to the previous one is subscriber-id, defined in RFC 4580. It is, too, inserted by a relay agent that is configured to insert it. This parameter can also be specified as rfc4580, which is an alias for subscriber-id. This method is currently not implemented.
  • docsis-cmts - Yet another possible source of MAC address information are the DOCSIS options inserted by a CMTS that acts as a DHCPv6 relay agent in cable networks. This method attempts to extract MAC address information from suboption 1026 (cm mac) of the vendor specific option with vendor-id=4491. This vendor option is extracted from the relay-forward message, not the original client's message.
  • docsis-modem - Yet another possible source of MAC address information are the DOCSIS options inserted by the cable modem itself. This method attempts to extract MAC address information from suboption 36 (device id) of the vendor specific option with vendor-id=4491. This vendor option is extracted from the original client's message, not from any relay options.

8.10. Duplicate Addresses (DECLINE Support)

The DHCPv6 server is configured with a certain pool of addresses that it is expected to hand out to the DHCPv6 clients. It is assumed that the server is authoritative and has complete jurisdiction over those addresses. However, due to various reasons, such as misconfiguration or a faulty client implementation that retains its address beyond the valid lifetime, there may be devices connected that use those addresses without the server's approval or knowledge.

Such an unwelcome event can be detected by legitimate clients (using Duplicate Address Detection) and reported to the DHCPv6 server using a DECLINE message. The server will do a sanity check (if the client declining an address really was supposed to use it), then will conduct a clean up operation and confirm it by sending back a REPLY message. Any DNS entries related to that address will be removed, the fact will be logged and hooks will be triggered. After that is done, the address will be marked as declined (which indicates that it is used by an unknown entity and thus not available for assignment to anyone) and a probation time will be set on it. Unless otherwise configured, the probation period lasts 24 hours. After that period, the server will recover the lease (i.e. put it back into the available state) and the address will be available for assignment again. It should be noted that if the underlying issue of a misconfigured device is not resolved, the duplicate address scenario will repeat. On the other hand, it provides an opportunity to recover from such an event automatically, without any sysadmin intervention.

To configure the decline probation period to a value other than the default, the following syntax can be used:

  "Dhcp6": {
    "decline-probation-period": 3600,
    "subnet6": [ ... ],
    ...
}

The parameter is expressed in seconds, so the example above will instruct the server to recycle declined leases after an hour.

There are several statistics and hook points associated with the Decline handling procedure. The lease6_decline hook is triggered after the incoming Decline message has been sanitized and the server is about to decline the lease. The declined-addresses statistic is increased after the hook returns (both global and subnet specific variants). (See Section 7.7, “Statistics in the DHCPv4 Server†and Chapter 13, Hooks Libraries for more details on DHCPv4 statistics and Kea hook points.)

Once the probation time elapses, the declined lease is recovered using the standard expired lease reclamation procedure, with several additional steps. In particular, both declined-addresses statistics (global and subnet specific) are decreased. At the same time, reclaimed-declined-addresses statistics (again in two variants, global and subnet specific) are increased.

Note about statistics: The server does not decrease the assigned-addresses statistics when a DECLINE message is received and processed successfully. While technically a declined address is no longer assigned, the primary usage of the assigned-addresses statistic is to monitor pool utilization. Most people would forget to include declined-addresses in the calculation, and simply do assigned-addresses/total-addresses. This would have a bias towards under-representing pool utilization. As this has a potential for major issues, we decided not to decrease assigned addresses immediately after receiving Decline, but to do it later when we recover the address back to the available pool.

8.11. Statistics in the DHCPv6 Server

Note

This section describes DHCPv6-specific statistics. For a general overview and usage of statistics, see Chapter 14, Statistics.

The DHCPv6 server supports the following statistics:

Table 8.4. DHCPv6 Statistics

StatisticData TypeDescription
pkt6-receivedintegerNumber of DHCPv6 packets received. This includes all packets: valid, bogus, corrupted, rejected etc. This statistic is expected to grow rapidly.
pkt6-receive-dropintegerNumber of incoming packets that were dropped. The exact reason for dropping packets is logged, but the most common reasons may be: an unacceptable or not supported packet type, direct responses are forbidden, the server-id sent by the client does not match the server's server-id or the packet is malformed.
pkt6-parse-failedintegerNumber of incoming packets that could not be parsed. A non-zero value of this statistic indicates that the server received a malformed or truncated packet. This may indicate problems in your network, faulty clients, faulty relay agents or a bug in the server.
pkt6-solicit-receivedinteger Number of SOLICIT packets received. This statistic is expected to grow. Its increase means that clients that just booted started their configuration process and their initial packets reached your server.
pkt6-advertise-receivedinteger Number of ADVERTISE packets received. Advertise packets are sent by the server and the server is never expected to receive them. A non-zero value of this statistic indicates an error occurring in the network. One likely cause would be a misbehaving relay agent that incorrectly forwards ADVERTISE messages towards the server rather back to the clients.
pkt6-request-receivedintegerNumber of REQUEST packets received. This statistic is expected to grow. Its increase means that clients that just booted received the server's response (ADVERTISE), accepted it and are now requesting an address (REQUEST).
pkt6-reply-receivedintegerNumber of REPLY packets received. This statistic is expected to remain zero at all times, as REPLY packets are sent by the server and the server is never expected to receive them. A non-zero value indicates an error. One likely cause would be a misbehaving relay agent that incorrectly forwards REPLY messages towards the server, rather back to the clients.
pkt6-renew-receivedintegerNumber of RENEW packets received. This statistic is expected to grow. Its increase means that clients received their addresses and prefixes and are trying to renew them.
pkt6-rebind-receivedintegerNumber of REBIND packets received. A non-zero value indicates that clients didn't receive responses to their RENEW messages (regular lease renewal mechanism) and are attempting to find any server that is able to take over their leases. It may mean that some server's REPLY messages never reached the clients.
pkt6-release-receivedintegerNumber of RELEASE packets received. This statistic is expected to grow when a device is being shut down in the network. It indicates that the address or prefix assigned is reported as no longer needed. Note that many devices, especially wireless, do not send RELEASE packets either because of design choice or due to the client moving out of range.
pkt6-decline-receivedinteger Number of DECLINE packets received. This statistic is expected to remain close to zero. Its increase means that a client leased an address, but discovered that the address is currently used by an unknown device in your network. If this statistic is growing, it may indicate a misconfigured server or devices that have statically assigned conflicting addresses.
pkt6-infrequest-receivedinteger Number of INFORMATION-REQUEST packets received. This statistic is expected to grow if there are devices that are using stateless DHCPv6. INFORMATION-REQUEST messages are used by clients that request stateless configuration, i.e. options and parameters other than addresses or prefixes.
pkt6-dhcpv4-query-receivedinteger Number of DHCPv4-QUERY packets received. This statistic is expected to grow if there are devices that are using DHCPv4-over-DHCPv6. DHCPv4-QUERY messages are used by DHCPv4 clients on an IPv6 only line which encapsulatesi the requests over DHCPv6.
pkt6-dhcpv4-response-receivedinteger Number of DHCPv4-RESPONSE packets received. This statistic is expected to remain zero at all times, as DHCPv4-RESPONSE packets are sent by the server and the server is never expected to receive them. A non-zero value indicates an error. One likely cause would be a misbehaving relay agent that incorrectly forwards DHCPv4-RESPONSE message towards the server rather back to the clients.
pkt6-unknown-receivedintegerNumber of packets received of an unknown type. A non-zero value of this statistic indicates that the server received a packet that it wasn't able to recognize: either it had an unsupported type or was possibly malformed.
pkt6-sentintegerNumber of DHCPv6 packets sent. This statistic is expected to grow every time the server transmits a packet. In general, it should roughly match pkt6-received, as most incoming packets cause the server to respond. There are exceptions (e.g. server receiving a REQUEST with server-id matching other server), so do not worry, if it is lesser than pkt6-received.
pkt6-advertise-sentintegerNumber of ADVERTISE packets sent. This statistic is expected to grow in most cases after a SOLICIT is processed. There are certain uncommon, but valid cases where incoming SOLICIT is dropped, but in general this statistic is expected to be close to pkt6-solicit-received.
pkt6-reply-sentintegerNumber of REPLY packets sent. This statistic is expected to grow in most cases after a SOLICIT (with rapid-commit), REQUEST, RENEW, REBIND, RELEASE, DECLINE or INFORMATION-REQUEST is processed. There are certain cases where there is no response.
pkt6-dhcpv4-response-sentintegerNumber of DHCPv4-RESPONSE packets sent. This statistic is expected to grow in most cases after a DHCPv4-QUERY is processed. There are certain cases where there is no response.
subnet[id].total-nasinteger This statistic shows the total number of NA addresses available for DHCPv6 management for a given subnet. In other words, this is the sum of all addresses in all configured pools. This statistic changes only during configuration changes. Note that it does not take into account any addresses that may be reserved due to host reservation. The id is the subnet-id of a given subnet. This statistic is exposed for each subnet separately and is reset during a reconfiguration event.
subnet[id].assigned-nasinteger This statistic shows the number of NA addresses in a given subnet that are assigned. This statistic increases every time a new lease is allocated (as a result of receiving a REQUEST message) and is decreased every time a lease is released (a RELEASE message is received) or expires. The id is the subnet-id of a given subnet. This statistic is exposed for each subnet separately and is reset during a reconfiguration event.
subnet[id].total-pdsinteger This statistic shows the total number of PD prefixes available for DHCPv6 management for a given subnet. In other words, this is the sum of all prefixes in all configured pools. This statistic changes only during configuration changes. Note it does not take into account any prefixes that may be reserved due to host reservation. The id is the subnet-id of a given subnet. This statistic is exposed for each subnet separately and is reset during a reconfiguration event.
subnet[id].assigned-pdsinteger This statistic shows the number of PD prefixes in a given subnet that are assigned. This statistic increases every time a new lease is allocated (as a result of receiving a REQUEST message) and is decreased every time a lease is released (a RELEASE message is received) or expires. The id is the subnet-id of a given subnet. This statistic is exposed for each subnet separately and is reset during a reconfiguration event.
declined-addressesinteger This statistic shows the number of IPv6 addresses that are currently declined and so counts the number of leases currently unavailable. Once a lease is recovered, this statistic will be decreased. Ideally, this statistic should be zero. If this statistic is non-zero (or worse, increasing), the network administrator should investigate if there is a misbehaving device in the network. This is a global statistic that covers all subnets.
subnet[id].declined-addressesinteger This statistic shows the number of IPv6 addresses that are currently declined in a given subnet. This statistic counts the number of leases currently unavailable. Once a lease is recovered, this statistic will be decreased. Ideally, this statistic should be zero. If this statistic is non-zero (or worse, increasing), a network administrator should investigate if there is a misbehaving device in the network. The id is the subnet-id of a given subnet. This statistic is exposed for each subnet separately.
reclaimed-declined-addressesinteger This statistic shows the number of IPv6 addresses that were declined, but have now been recovered. Unlike declined-addresses, this statistic never decreases. It can be used as a long term indicator of how many actual valid Declines were processed and recovered from. This is a global statistic that covers all subnets.
subnet[id].reclaimed-declined-addressesinteger This statistic shows the number of IPv6 addresses that were declined, but have now been recovered. Unlike declined-addresses, this statistic never decreases. It can be used as a long term indicator of how many actual valid Declines were processed and recovered from. The id is the subnet-id of a given subnet. This statistic is exposed for each subnet separately.

8.12. Management API for the DHCPv6 Server

The management API allows the issuing of specific management commands, such as statistics retrieval, reconfiguration or shutdown. For more details, see Chapter 15, Management API. Currently the only supported communication channel type is UNIX stream socket. By default there are no sockets open. To instruct Kea to open a socket, the following entry in the configuration file can be used:

"Dhcp6": {
    "control-socket": {
        "socket-type": "unix",
        "socket-name": "/path/to/the/unix/socket"
    },

    "subnet6": [
        ...
    ],
    ...
}

The length of the path specified by the socket-name parameter is restricted by the maximum length for the unix socket name on your operating system, i.e. the size of the sun_path field in the sockaddr_un structure, decreased by 1. This value varies on different operating systems between 91 and 107 characters. Typical values are 107 on Linux and 103 on FreeBSD.

Communication over control channel is conducted using JSON structures. See the Control Channel section in the Kea Developer's Guide for more details.

The DHCPv6 server supports statistic-get, statistic-reset, statistic-remove, statistic-get-all, statistic-reset-all and statistic-remove-all, specified in Section 14.3, “Commands for Manipulating Statisticsâ€. It also supports list-commands and shutdown, specified in Section 15.3.2, “list-commands†and Section 15.3.3, “shutdownâ€, respectively.

8.13. Supported DHCPv6 Standards

The following standards are currently supported:

  • Dynamic Host Configuration Protocol for IPv6, RFC 3315: Supported messages are SOLICIT, ADVERTISE, REQUEST, RELEASE, RENEW, REBIND, INFORMATION-REQUEST, CONFIRM and REPLY.
  • IPv6 Prefix Options for Dynamic Host Configuration Protocol (DHCP) version 6, RFC 3633: Supported options are IA_PD and IA_PREFIX. Also supported is the status code NoPrefixAvail.
  • DNS Configuration options for Dynamic Host Configuration Protocol for IPv6 (DHCPv6), RFC 3646: Supported option is DNS_SERVERS.
  • The Dynamic Host Configuration Protocol for IPv6 (DHCPv6) Relay Agent Remote-ID Option, RFC 4649: REMOTE-ID option is supported.
  • The Dynamic Host Configuration Protocol for IPv6 (DHCPv6) Client Fully Qualified Domain Name (FQDN) Option, RFC 4704: Supported option is CLIENT_FQDN.
  • Relay-Supplied DHCP Options, RFC 6422: Full functionality is supported: OPTION_RSOO, ability of the server to echo back the options, checks whether an option is RSOO-enabled, ability to mark additional options as RSOO-enabled.
  • Client Link-Layer Address Option in DHCPv6, RFC 6939: Supported option is client link-layer address option.
  • Issues and Recommendations with Multiple Stateful DHCPv6 Options, RFC 7550: All recommendations related to the DHCPv6 server operation are supported.

8.14. DHCPv6 Server Limitations

These are the current limitations of the DHCPv6 server software. Most of them are reflections of the early stage of development and should be treated as “not implemented yetâ€, rather than actual limitations.

  • The server will allocate, renew or rebind a maximum of one lease for a particular IA option (IA_NA or IA_PD) sent by a client. RFC 3315 and RFC 3633 allow for multiple addresses or prefixes to be allocated for a single IA.
  • Temporary addresses are not supported.
  • Client reconfiguration (RECONFIGURE) is not yet supported.

Chapter 9. Lease Expiration in DHCPv4 and DHCPv6

The primary role of the DHCP server is to assign addresses and/or delegate prefixes to DHCP clients. These addresses and prefixes are often referred to as "leases". Leases are typically assigned to clients for a finite amount of time, known as the "valid lifetime". DHCP clients who wish to continue using their assigned leases, will periodically renew them by sending the appropriate message to the DHCP server. The DHCP server records the time when these leases are renewed and calculates new expiration times for them.

If the client does not renew a lease before its valid lifetime elapses, the lease is considered expired. There are many situations when the client may cease lease renewals. A common scenario is when the machine running the client shuts down for an extended period of time.

The process through which the DHCP server makes expired leases available for reassignment is referred to as "lease reclamation" and expired leases returned to availability through this process are referred to as "reclaimed". The DHCP server attempts to reclaim an expired lease as soon as it detects that it has expired. One way in which the server detects expiration occurs when it is trying to allocate a lease to a client and finds this lease already present in the database but expired. Another way is by periodically querying the lease database for them. Regardless of how an expired lease is detected, before it may assigned to a client, it must be reclaimed.

This chapter explains how to configure the server to periodically query for the expired leases and how to minimize the impact of the periodic lease reclamation process on the server's responsiveness. Finally, it explains "lease affinity", which provides the means to assign the same lease to a returning client after its lease has expired.

Although, all configuration examples in this section are provided for the DHCPv4 server, the same parameters may be used for the DHCPv6 server configuration.

9.1. Lease Reclamation

Lease reclamation is the process through which an expired lease becomes available for assignment to the same or different client. This process involves the following steps for each reclaimed lease:

  • Invoke callouts for the lease4_expire or lease6_expire hook points if hook libraries supporting those callouts are currently loaded.
  • Update DNS, i.e. remove any DNS entries associated with the expired lease.
  • Update lease information in the lease database to indicate that the lease is now available for re-assignment.
  • Update counters on the server, which includes increasing the number of reclaimed leases and decreasing the number of assigned addresses or delegated prefixes.

Please refer to Chapter 10, The DHCP-DDNS Server to see how to configure DNS updates in Kea, and to Chapter 13, Hooks Libraries for information about using hooks libraries.

9.2. Configuring Lease Reclamation

Kea can be configured to periodically detect and reclaim expired leases. During this process the lease entries in the database are modified or removed. While this is happening the server will not process incoming DHCP messages to avoid issues with concurrent access to database information. As a result, the server will be unresponsive while lease reclamation is performed and DHCP queries will accumulate; responses will be sent once the leases reclamation cycle is complete.

In deployments where response time is critical, administrators may wish to minimize the interruptions in service caused by lease reclamation. Toward this end, Kea provides configuration parameters to control: the frequency of lease reclamation cycles, the maximum number of leases processed in a single reclamation cycle, and the maximum amount of time a single reclamation cycle is allowed to run before being interrupted. The following examples demonstrate how these parameters can be used:

"Dhcp4": {
    ...

    "expired-leases-processing": {
        "reclaim-timer-wait-time": 5,
        "max-reclaim-leases": 0,
        "max-reclaim-time": 0,
        "flush-reclaimed-timer-wait-time": 0,
    },

    ...
}

The first parameter is expressed in seconds and specifies an interval between the two consecutive lease reclamation cycles. This is explained by the following diagram.


|  c1  |            | c2 |            |c3|            | c4 |
|<---->|<---------->|<-->|<---------->|<>|<---------->|<-->|
---------------------------------------------------------------->
|      |     5s     |    |     5s     |  |     5s     |    | time

This diagram shows four lease reclamation cycles (c1 through c4) of variable duration. Note that the duration of the reclamation cycle depends on the number of expired leases detected and processed in the particular cycle. This duration is also usually significantly shorter than the interval between the cycles.

According to the reclaim-timer-wait-time the server keeps fixed intervals of five seconds between the end of one cycle and the start of the next cycle. This guarantees the presence of 5s long periods during which the server remains responsive to DHCP queries and does not perform lease reclamation. The max-reclaim-leases and max-reclaim-time are set to 0, which sets no restriction on the maximum number of leases reclaimed in the particular cycle, or on the maximum duration of each cycle.

In deployments with high lease pool utilization, relatively short valid lifetimes, and frequently disconnecting clients which allow leases to expire, the number of expired leases requiring reclamation at any given time may rise significantly. In this case it is often desirable to apply restrictions on the maximum duration of a reclamation cycle or the maximum number of leases reclaimed in a cycle. The following configuration demonstrates how this can be done:

"Dhcp4": {
    ...

    "expired-leases-processing": {
        "reclaim-timer-wait-time": 3,
        "max-reclaim-leases": 100,
        "max-reclaim-time": 50,
        "unwarned-reclaim-cycles": 10,
    },

    ...
}

The max-reclaim-leases parameter limits the number of leases reclaimed in a single cycle to 100. The max-reclaim-time limits the maximum duration of each cycle to 50ms. The lease reclamation cycle will be interrupted if either of these limitations is reached. The reclamation of all unreclaimed leases will be attempted in subsequent cycles.

The following diagram illustrates the behavior of the system in the presence of many expired leases, when the limits are applied for the reclamation cycles.


| c1 |                | c2 |                | c3 |                | c4 |
|<-->|<-------------->|<-->|<-------------->|<-->|<-------------->|<-->|<--
------------------------------------------------------------------------------>
|50ms|       3s       |50ms|       3s       |50ms|       3s       |50ms|  time

The diagram demonstrates the case when each reclamation cycle would take more than 50ms, and thus is interrupted according to the value of the max-reclaim-time. This results in equal durations of all reclamation cycles over time. Note that in this example the limitation of maximum 100 leases is not reached. This may be the case when database transactions are slow or callouts in the hook libraries attached to the server are slow. Regardless, the choosing values for either the maximum number of leases or a maximum cycle time strongly depends on the particular deployment, lease database backend being used, and any hooks libraries etc. Administrators may need to experiment to tune the system to suit the dynamics of their deployment.

It is important to realize that with the use of these limits, there is a risk that expired leases will accumulate faster than the server can reclaim them. This should not be the problem if the server is dealing with a temporary burst of expirations, because it should be able to eventually deal with them over time. However, if leases expire at a high rate for a longer period of time, the unreclaimed leases will pile up in the database. In order to notify the administrator that the current configuration does not satisfy the needs for reclamation of expired leases, the server issues a warning message in the log if it was unable to reclaim all leases within the last couple of reclamation cycles. The number of cycles after which such warning is issued is specified with the unwarned-reclaim-cycles configuration parameter.

Setting the reclaim-timer-wait-time to 0 disables periodic reclamation of the expired leases.

9.3. Configuring Lease Affinity

Suppose that a laptop goes to a sleep mode after a period of user inactivity. While the laptop is in sleep mode, its DHCP client will not renew leases obtained from the server and these leases will eventually expire. When the laptop wakes up, it is often desirable for it to continue using its previous assigned IP addresses. In order to facilitate this, the server needs to correlate returning clients with their expired leases When the client returns, the server will first check for those leases and re-assign them if they have not been assigned to another client. The ability of the server to re-assign the same lease to a returning client is referred to as "lease affinity".

When lease affinity is enabled, the server will still reclaim leases according to the parameters described in Section 9.2, “Configuring Lease Reclamationâ€, but the reclaimed leases will be held in the database (rather than removed) for the specified amount of time. When the client returns, the server will first check if there are any reclaimed leases associated with this client and re-assign them if possible. However, it is important to note that any reclaimed lease may be assigned to another client if that client specifically asks for it. Therefore, the lease affinity does not guarantee that the reclaimed lease will be available for the client who used it before; it merely increases the chances for the client to be assigned the same lease. If the lease pool is small (this mostly applies to DHCPv4 for which address space is small), there is an increased likelihood that the expired lease will be assigned to another client.

Consider the following configuration:

"Dhcp4": {
    ...

    "expired-leases-processing": {
        "reclaim-timer-wait-time": 3,
        "hold-reclaimed-time": 1800,
        "flush-reclaimed-timer-wait-time": 5
    },

    ...
}

The hold-reclaim-time specifies how many seconds after an expiration a reclaimed lease should be held in the database for re-assignment to the same client. In the example given above, reclaimed leases will be held for 30 minutes (1800s) after their expiration. During this time, the server will likely be able to re-assign the same lease to the returning client, unless another client requests this lease and the server assigns it.

The server must periodically remove reclaimed leases for which the time indicated by hold-reclaim-time has elapsed. The flush-reclaimed-timer-wait-time controls how often the server removes such leases. In the example provided above, the server will initiate removal of such leases 5 seconds after the previous removal attempt was completed. Setting this value to 0 disables lease affinity, in which case leases will be removed from the lease database when they are reclaimed. If lease affinity is enabled, it is recommended that hold-reclaim-time be set to a value significantly higher than the reclaim-timer-wait-time, as timely removal of expired-reclaimed leases is less critical while the removal process may impact server responsiveness.

9.4. Default Configuration Values for Leases Reclamation

The following list presents all configuration parameters pertaining to processing expired leases with their default values:

  • reclaim-timer-wait-time = 10 [seconds]
  • flush-reclaimed-timer-wait-time = 25 [seconds]
  • hold-reclaimed-time = 3600 [seconds]
  • max-reclaim-leases = 100
  • max-reclaim-time = 250 [milliseconds]
  • unwarned-reclaim-cycles = 5

The default value for any parameter is used when this parameter not explicitly specified in the configuration. Also, the expired-leases-processing map may be omitted entirely in the configuration, in which case the default values are used for all parameters listed above.

9.5. Reclaiming Expired Leases with Command

The leases-reclaim command can be used to trigger leases reclamation at any time. Please consult the Section 15.3.1, “leases-reclaim†for the details about using this command.

Chapter 10. The DHCP-DDNS Server

The DHCP-DDNS Server (kea-dhcp-ddns, known informally as D2) conducts the client side of the DDNS protocol (defined in RFC 2136) on behalf of the DHCPv4 and DHCPv6 servers (kea-dhcp4 and kea-dhcp6 respectively). The DHCP servers construct DDNS update requests, known as NameChangeRequests (NCRs), based upon DHCP lease change events and then post these to D2. D2 attempts to match each such request to the appropriate DNS server(s) and carry out the necessary conversation with those servers to update the DNS data.

In order to match a request to the appropriate DNS servers, D2 must have a catalog of servers from which to select. In fact, D2 has two such catalogs, one for forward DNS and one for reverse DNS; these catalogs are referred to as DDNS Domain Lists. Each list consists of one or more named DDNS Domains. Further, each DDNS Domain has a list of one or more DNS servers that publish the DNS data for that domain.

When conducting forward domain matching, D2 will compare the FQDN in the request against the name of each forward DDNS Domain. The domain whose name matches the longest portion of the FQDN is considered the best match. For example, if the FQDN is "myhost.sample.example.com.", and there are two forward domains in the catalog: "sample.example.com." and "example.com.", the former is regarded as the best match. In some cases, it may not be possible to find a suitable match. Given the same two forward domains there would be no match for the FQDN, "bogus.net", so the request would be rejected. Finally, if there are no forward DDNS Domains defined, D2 will simply disregard the forward update portion of requests.

When conducting reverse domain matching, D2 constructs a reverse FQDN from the lease address in the request and compare that against the name of each reverse DDNS Domain. Again, the domain whose name matches the longest portion of the FQDN is considered the best match. For instance, if the lease address is "172.16.1.40" and there are two reverse domains in the catalog: "1.16.172.in-addr.arpa." and "16.172.in-addr.arpa", the former is the best match. As with forward matching, it is possible to not find a suitable match. Given the same two domains, there would be no match for the lease address, "192.168.1.50", and the request would be rejected. Finally, if there are no reverse DDNS Domains defined, D2 will simply disregard the reverse update portion of requests.

10.1. Starting and Stopping the DHCP-DDNS Server

kea-dhcp-ddns is the Kea DHCP-DDNS server and, due to the nature of DDNS, it is run alongside either the DHCPv4 or DHCPv6 components (or both). Like other parts of Kea, it is a separate binary that can be run on its own or through keactrl (see Chapter 6, Managing Kea with keactrl). In normal operation, controlling kea-dhcp-ddns with keactrl is recommended. However, it is also possible to run the DHCP-DDNS server directly. It accepts the following command-line switches:

  • -c file - specifies the configuration file. This is the only mandatory switch.
  • -d - specifies whether the server logging should be switched to debug/verbose mode. In verbose mode, the logging severity and debuglevel specified in the configuration file are ignored and "debug" severity and the maximum debuglevel (99) are assumed. The flag is convenient, for temporarily switching the server into maximum verbosity, e.g. when debugging.
  • -v - prints out Kea version and exits.
  • -W - prints out the Kea configuration report and exits. The report is a copy of the config.report file produced by ./configure: it is embedded in the executable binary.
  • -W - prints out Kea configuration report and exits.

The config.report may also be accessed more directly. The following command may be used to extract this information. The binary path may be found in the install directory or in the .libs subdirectory in the source tree. For example kea/src/bin/d2/.libs/kea-dhcp-ddns.

strings path/kea-dhcp-ddns | sed -n 's/;;;; //p'

Upon start up the module will load its configuration and begin listening for NCRs based on that configuration.

During startup the server will attempt to create a PID file of the form: [localstatedir]/[conf name].kea-dhcp-ddns.pid where:

  • localstatedir: The value as passed into the build configure script. It defaults to "/usr/local/var". Note that this value may be overridden at run time by setting the environment variable KEA_PIDFILE_DIR. This is intended primarily for testing purposes.
  • conf name: The configuration file name used to start the server, minus all preceding path and file extension. For example, given a pathname of "/usr/local/etc/kea/myconf.txt", the portion used would be "myconf".

If the file already exists and contains the PID of a live process, the server will issue a DHCP_DDNS_ALREADY_RUNNING log message and exit. It is possible, though unlikely, that the file is a remnant of a system crash and the process to which the PID belongs is unrelated to Kea. In such a case it would be necessary to manually delete the PID file.

10.2. Configuring the DHCP-DDNS Server

Before starting kea-dhcp-ddns module for the first time, a configuration file needs to be created. The following default configuration is a template that can be customised to your requirements.

"DhcpDdns": {
    "ip-address": "127.0.0.1",
    "port": 53001,
    "dns-server-timeout": 100,
    "ncr-protocol": "UDP",
    "ncr-format": "JSON",
    "tsig-keys": [ ],
    "forward-ddns": {
	"ddns-domains": [ ]
    },
    "reverse-ddns": {
	"ddns-domains": [ ]
    }
}

The configuration can be divided as follows, each of which is described in its own section:

  • Global Server Parameters - values which control connectivity and global server behavior
  • TSIG Key Info - defines the TSIG keys used for secure traffic with DNS servers
  • Forward DDNS - defines the catalog of Forward DDNS Domains
  • Reverse DDNS - defines the catalog of Forward DDNS Domains

10.2.1. Global Server Parameters

  • ip-address - IP address on which D2 listens for requests. The default is the local loopback interface at address 127.0.0.1. You may specify either an IPv4 or IPv6 address.
  • port - Port on which D2 listens for requests. The default value is 53001.
  • dns-server-timeout - The maximum amount of time in milliseconds, that D2 will wait for a response from a DNS server to a single DNS update message.
  • ncr-protocol - Socket protocol to use when sending requests to D2. Currently only UDP is supported. TCP may be available in a future release.
  • ncr-format - Packet format to use when sending requests to D2. Currently only JSON format is supported. Other formats may be available in future releases.

D2 must listen for change requests on a known address and port. By default it listens at 127.0.0.1 on port 53001. The following example illustrates how to change D2's global parameters so it will listen at 192.168.1.10 port 900:

"DhcpDdns": {
    "ip-address": "192.168.1.10",
    "port": 900,
    ...
    }
}

Warning

It is possible for a malicious attacker to send bogus NameChangeRequests to the DHCP-DDNS server. Addresses other than the IPv4 or IPv6 loopback addresses (127.0.0.1 or ::1) should only be used for testing purposes, but note that local users may still communicate with the DHCP-DDNS server. A future version of Kea will implement authentication to guard against such attacks.

Note

If the ip-address and port are changed, it will be necessary to change the corresponding values in the DHCP servers' "dhcp-ddns" configuration section.

10.2.2. TSIG Key List

A DDNS protocol exchange can be conducted with or without TSIG (defined in RFC 2845). This configuration section allows the administrator to define the set of TSIG keys that may be used in such exchanges.

To use TSIG when updating entries in a DNS Domain, a key must be defined in the TSIG Key List and referenced by name in that domain's configuration entry. When D2 matches a change request to a domain, it checks whether the domain has a TSIG key associated with it. If so, D2 will use that key to sign DNS update messages sent to and verify responses received from the domain's DNS server(s). For each TSIG key required by the DNS servers that D2 will be working with there must be a corresponding TSIG key in the TSIG Key list.

As one might gather from the name, the tsig-key section of the D2 configuration lists the TSIG keys. Each entry describes a TSIG key used by one or more DNS servers to authenticate requests and sign responses. Every entry in the list has three parameters:

  • name - a unique text label used to identify this key within the list. This value is used to specify which key (if any) should be used when updating a specific domain. So long as it is unique its content is arbitrary, although for clarity and ease of maintenance it is recommended that it match the name used on the DNS server(s). It cannot be blank.
  • algorithm - specifies which hashing algorithm should be used with this key. This value must specify the same algorithm used for the key on the DNS server(s). The supported algorithms are listed below:
    • HMAC-MD5
    • HMAC-SHA1
    • HMAC-SHA224
    • HMAC-SHA256
    • HMAC-SHA384
    • HMAC-SHA512
    This value is not case sensitive.
  • digest-bits - is used to specify the minimum truncated length in bits. The default value 0 means truncation is forbidden, non-zero values must be an integral number of octets, be greater than 80 and the half of the full length. Note in BIND9 this parameter is appended after a dash to the algorithm name.
  • secret - is used to specify the shared secret key code for this key. This value is case sensitive and must exactly match the value specified on the DNS server(s). It is a base64-encoded text value.

As an example, suppose that a domain D2 will be updating is maintained by a BIND9 DNS server which requires dynamic updates to be secured with TSIG. Suppose further that the entry for the TSIG key in BIND9's named.conf file looks like this:

   :
   key "key.four.example.com." {
       algorithm hmac-sha224;
       secret "bZEG7Ow8OgAUPfLWV3aAUQ==";
   };
   :

By default, the TSIG Key list is empty:

"DhcpDdns": {
   "tsig-keys": [ ],
   ...
}

We must extend the list with a new key:

"DhcpDdns": {
    "tsig-keys": [
        {
	    "name": "key.four.example.com.",
	    "algorithm": "HMAC-SHA224",
	    "secret": "bZEG7Ow8OgAUPfLWV3aAUQ=="
	}
    ],
    ...
}

These steps would be repeated for each TSIG key needed. Note that the same TSIG key can be used with more than one domain.

10.2.3. Forward DDNS

The Forward DDNS section is used to configure D2's forward update behavior. Currently it contains a single parameter, the catalog of forward DDNS Domains, which is a list of structures.

"DhcpDdns": {
    "forward-ddns": {
	"ddns-domains": [ ]
    },
    ...
}

By default, this list is empty, which will cause the server to ignore the forward update portions of requests.

10.2.3.1. Adding Forward DDNS Domains

A forward DDNS Domain maps a forward DNS zone to a set of DNS servers which maintain the forward DNS data (i.e. name to address mapping) for that zone. You will need one forward DDNS Domain for each zone you wish to service. It may very well be that some or all of your zones are maintained by the same servers. You will still need one DDNS Domain per zone. Remember that matching a request to the appropriate server(s) is done by zone and a DDNS Domain only defines a single zone.

This section describes how to add Forward DDNS Domains. Repeat these steps for each Forward DDNS Domain desired. Each Forward DDNS Domain has the following parameters:

  • name - The fully qualified domain name (or zone) that this DDNS Domain can update. This is value used to compare against the request FQDN during forward matching. It must be unique within the catalog.
  • key-name - If TSIG is used with this domain's servers, this value should be the name of the key from within the TSIG Key List to use. If the value is blank (the default), TSIG will not be used in DDNS conversations with this domain's servers.
  • dns-servers - A list of one or more DNS servers which can conduct the server side of the DDNS protocol for this domain. The servers are used in a first to last preference. In other words, when D2 begins to process a request for this domain it will pick the first server in this list and attempt to communicate with it. If that attempt fails, it will move to next one in the list and so on until the it achieves success or the list is exhausted.

To create a new forward DDNS Domain, one must add a new domain element and set its parameters:

"DhcpDdns": {
    "forward-ddns": {
	"ddns-domains": [
	    {
		"name": "other.example.com.",
		"key-name": "",
		"dns-servers": [
		]
	    }
	]
    }
}

It is permissible to add a domain without any servers. If that domain should be matched to a request, however, the request will fail. In order to make the domain useful though, we must add at least one DNS server to it.

10.2.3.1.1. Adding Forward DNS Servers

This section describes how to add DNS servers to a Forward DDNS Domain. Repeat them for as many servers as desired for a each domain.

Forward DNS Server entries represent actual DNS servers which support the server side of the DDNS protocol. Each Forward DNS Server has the following parameters:

  • hostname - The resolvable host name of the DNS server. This value is not yet implemented.
  • ip-address - The IP address at which the server listens for DDNS requests. This may be either an IPv4 or an IPv6 address.
  • port - The port on which the server listens for DDNS requests. It defaults to the standard DNS service port of 53.

To create a new forward DNS Server, one must add a new server element to the domain and fill in its parameters. If for example the service is running at "172.88.99.10", then set it as follows:

"DhcpDdns": {
    "forward-ddns": {
	"ddns-domains": [
	    {
		"name": "other.example.com.",
		"key-name": "",
		"dns-servers": [
		    {
			"hostname": "",
			"ip-address": "172.88.99.10",
			"port": 53
		    }
		]
	    }
	]
    }
}

Note

As stated earlier, "hostname" is not yet supported so, the parameter "ip-address" must be set to the address of the DNS server.

10.2.4. Reverse DDNS

The Reverse DDNS section is used to configure D2's reverse update behavior, and the concepts are the same as for the forward DDNS section. Currently it contains a single parameter, the catalog of reverse DDNS Domains, which is a list of structures.

"DhcpDdns": {
    "reverse-ddns": {
	"ddns-domains": [ ]
    }
    ...
}

By default, this list is empty, which will cause the server to ignore the reverse update portions of requests.

10.2.4.1. Adding Reverse DDNS Domains

A reverse DDNS Domain maps a reverse DNS zone to a set of DNS servers which maintain the reverse DNS data (address to name mapping) for that zone. You will need one reverse DDNS Domain for each zone you wish to service. It may very well be that some or all of your zones are maintained by the same servers; even then, you will still need one DDNS Domain entry for each zone. Remember that matching a request to the appropriate server(s) is done by zone and a DDNS Domain only defines a single zone.

This section describes how to add Reverse DDNS Domains. Repeat these steps for each Reverse DDNS Domain desired. Each Reverse DDNS Domain has the following parameters:

  • name - The fully qualified reverse zone that this DDNS Domain can update. This is the value used during reverse matching which will compare it with a reversed version of the request's lease address. The zone name should follow the appropriate standards: for example, to to support the IPv4 subnet 172.16.1, the name should be. "1.16.172.in-addr.arpa.". Similarly, to support an IPv6 subnet of 2001:db8:1, the name should be "1.0.0.0.8.B.D.0.1.0.0.2.ip6.arpa." Whatever the name, it must be unique within the catalog.
  • key-name - If TSIG should be used with this domain's servers, then this value should be the name of that key from the TSIG Key List. If the value is blank (the default), TSIG will not be used in DDNS conversations with this domain's servers. Currently this value is not used as TSIG has not been implemented.
  • dns-servers - a list of one or more DNS servers which can conduct the server side of the DDNS protocol for this domain. Currently the servers are used in a first to last preference. In other words, when D2 begins to process a request for this domain it will pick the first server in this list and attempt to communicate with it. If that attempt fails, it will move to next one in the list and so on until the it achieves success or the list is exhausted.

To create a new reverse DDNS Domain, one must add a new domain element and set its parameters. For example, to support subnet 2001:db8:1::, the following configuration could be used:

"DhcpDdns": {
    "reverse-ddns": {
	"ddns-domains": [
	    {
		"name": "1.0.0.0.8.B.D.0.1.0.0.2.ip6.arpa.",
		"key-name": "",
		"dns-servers": [
		]
	    }
	]
    }
}

It is permissible to add a domain without any servers. If that domain should be matched to a request, however, the request will fail. In order to make the domain useful though, we must add at least one DNS server to it.

10.2.4.1.1. Adding Reverse DNS Servers

This section describes how to add DNS servers to a Reverse DDNS Domain. Repeat them for as many servers as desired for each domain.

Reverse DNS Server entries represents a actual DNS servers which support the server side of the DDNS protocol. Each Reverse DNS Server has the following parameters:

  • hostname - The resolvable host name of the DNS server. This value is currently ignored.
  • ip-address - The IP address at which the server listens for DDNS requests.
  • port - The port on which the server listens for DDNS requests. It defaults to the standard DNS service port of 53.

To create a new reverse DNS Server, one must first add a new server element to the domain and fill in its parameters. If for example the service is running at "172.88.99.10", then set it as follows:

"DhcpDdns": {
    "reverse-ddns": {
	"ddns-domains": [
	    {
		"name": "1.0.0.0.8.B.D.0.1.0.0.2.ip6.arpa.",
		"key-name": "",
		"dns-servers": [
		    {
			"hostname": "",
			"ip-address": "172.88.99.10",
			"port": 53
		    }
		]
	    }
	]
    }
}

Note

As stated earlier, "hostname" is not yet supported so, the parameter "ip-address" must be set to the address of the DNS server.

10.2.5. Example DHCP-DDNS Server Configuration

This section provides an example DHCP-DDNS server configuration based on a small example network. Let's suppose our example network has three domains, each with their own subnet.

Table 10.1. Our example network

DomainSubnetForward DNS ServersReverse DNS Servers
four.example.com192.0.2.0/24172.16.1.5, 172.16.2.5172.16.1.5, 172.16.2.5
six.example.com2001:db8:1::/643001:1::503001:1::51
example.com192.0.0.0/16172.16.2.5172.16.2.5


We need to construct three forward DDNS Domains:

Table 10.2. Forward DDNS Domains Needed

#DDNS Domain NameDNS Servers
1.four.example.com.172.16.1.5, 172.16.2.5
2.six.example.com.3001:1::50
3.example.com.172.16.2.5


As discussed earlier, FQDN to domain matching is based on the longest match. The FQDN, "myhost.four.example.com.", will match the first domain ("four.example.com") while "admin.example.com." will match the third domain ("example.com"). The FQDN, "other.example.net." will fail to match any domain and would be rejected.

The following example configuration specified the Forward DDNS Domains.


"DhcpDdns": {
    "forward-ddns": {
	"ddns-domains": [
	    {
		"name": "four.example.com.",
		"key-name": "",
		"dns-servers": [
		    { "ip-address": "172.16.1.5" },
		    { "ip-address": "172.16.2.5" }
		]
	    },
	    {
		"name": "six.example.com.",
		"key-name": "",
		"dns-servers": [
		    { "ip-address": "2001:db8::1" }
		]
	    },
	    {
		"name": "example.com.",
		"key-name": "",
		"dns-servers": [
		    { "ip-address": "172.16.2.5" }
		]
	    },

	]
    }
}

Similarly, we need to construct the three reverse DDNS Domains:

Table 10.3. Reverse DDNS Domains Needed

#DDNS Domain NameDNS Servers
1.2.0.192.in-addr.arpa.172.16.1.5, 172.16.2.5
2.1.0.0.0.8.d.b.0.1.0.0.2.ip6.arpa.3001:1::50
3.0.182.in-addr.arpa.172.16.2.5


An address of "192.0.2.150" will match the first domain, "2001:db8:1::10" will match the second domain, and "192.0.50.77" the third domain.

These Reverse DDNS Domains are specified as follows:


"DhcpDdns": {
    "reverse-ddns": {
	"ddns-domains": [
	    {
		"name": "2.0.192.in-addr.arpa.",
		"key-name": "",
		"dns-servers": [
		    { "ip-address": "172.16.1.5" },
		    { "ip-address": "172.16.2.5" }
		]
	    }
	    {
		"name": "1.0.0.0.8.B.D.0.1.0.0.2.ip6.arpa.",
		"key-name": "",
		"dns-servers": [
		    { "ip-address": "2001:db8::1" }
		]
	    }
	    {
		"name": "0.192.in-addr.arpa.",
		"key-name": "",
		"dns-servers": [
		    { "ip-address": "172.16.2.5" }
		]
	    }
	]
    }
}

10.3. DHCP-DDNS Server Limitations

The following are the current limitations of the DHCP-DDNS Server.

  • Requests received from the DHCP servers are placed in a queue until they are processed. Currently all queued requests are lost when the server shuts down.

Chapter 11. The LFC process

11.1. Overview

kea-lfc is a service process that removes redundant information from the files used to provide persistent storage for the memfile data base backend. This service is written to run as a stand alone process.

While kea-lfc can be started externally, there is usually no need to do this. kea-lfc is run on a periodic basis by the Kea DHCP servers.

The process operates on a set of files, using them for input and output of the lease entries and to indicate where it is in the process in case of an interruption. Currently the caller must supply names for all of the files, in the future this requirement may be relaxed with the process getting the names from either the configuration file or from defaults.

11.2. Command Line Options

kea-lfc is run as follows:

kea-lfc [-4 | -6] -c config-file -p pid-file -x previous-file -i copy-file -o output-file -f finish-file

The argument -4 or -6 selects the protocol version of the lease files.

The -c argument specifies the configuration file. This is required, but not currently used by the process.

The -p argument specifies the PID file. When the kea-lfc process starts it attempts to determine if another instance of the process is already running by examining the pid file. If one is already running the new process is terminated. If one isn't running it writes its pid into the pid file.

The other filenames specify where the kea-lfc process should look for input, write its output and use for bookkeeping.

  • previous — When kea-lfc starts this is the result of any previous run of kea-lfc. When kea-lfc finishes it is the result of this run. If kea-lfc is interrupted before completing, this file may not exist.
  • input — Before the DHCP server invokes kea-lfc it will move the current lease file here and then call kea-lfc with this file.
  • output — The temporary file kea-lfc should use to write the leases. Upon completion of writing this file, it will be moved to the finish file (see below).
  • finish — Another temporary file kea-lfc uses for bookkeeping. When kea-lfc completes writing the outputfile it moves it to this file name. After kea-lfc finishes deleting the other files (previous and input) it moves this file to previous lease file. By moving the files in this fashion the kea-lfc and the DHCP server processes can determine the correct file to use even if one of the processes was interrupted before completing its task.

There are several additional arguments mostly for debugging purposes. -d Sets the logging level to debug. -v and -V print out version stamps with -V providing a longer form. -h prints out the usage string.

Chapter 12. Client Classification

12.1. Client Classification Overview

In certain cases it is useful to differentiate between different types of clients and treat them accordingly. Common reasons include:

  • The clients represent different pieces of topology, e.g. a cable modem is different to the clients behind that modem.

  • The clients have different behavior, e.g. a smart phone behaves differently to a laptop.

  • The clients require different values for some options, e.g. a docsis3.0 cable modem requires different settings to docsis2.0 cable modem.

It is envisaged that client classification will be used for changing the behavior of almost any part of the DHCP message processing, including the assignment of leases from different pools, the assignment of different options (or different values of the same options) etc. In the current release of the software however, there are only three mechanisms that take advantage of client classification: subnet selection, assignment of different options and, for DHCPv4 cable modems, the setting of specific options for use with the TFTP server address and the boot file field.

The process of doing classification is conducted in three steps:

  1. Assess an incoming packet and assign it to zero or more classes.

  2. Choose a subnet, possibly based on the class information.

  3. Assign options, again possibly based on the class information.

When determining which options to include in the response the server will examine the union of options from all of the assigned classes. In the case two or more classes include the same option, the value from the first class examined will be used. When choosing a subnet, the server will iterate over all of the subnets that are feasible given the information found in the packet (client address, relay address etc). It will use the first subnet it finds that either doesn't have a class associated with it or that has a class which matches one of the packet's classes. In the future the processing order of the various classes may be specified but for now it is being left unspecified and may change in future releases.

As an example, imagine that an incoming packet matches two classes. Class "foo" defines values for an NTP server (option 42 in DHCPv4) and an SMTP server (option 69 in DHCPv4) while class "bar" defines values for an NTP server and a POP3 server (option 70 in DHCPv4). The server will examine the three options NTP, SMTP and POP3 and return any of them that the client requested. As the NTP server was defined twice the server will choose only one of the values for the reply: the class from which the value is obtained is unspecified.

There are two methods of doing classification. The first is automatic and relies on examining the values in the vendor class options. Information from these options is extracted and a class name is constructed from it and added to the class list for the packet. The second allows you to specify an expression that is evaluated for each packet. If the result is true, the packet is a member of the class.

Note

Care should be taken with client classification as it is easy for clients that do not meet class criteria to be denied any service altogether.

12.2. Using Static Host Reservations In Classification

Classes can be statically assigned to the clients using techniques described in Section 7.3.6, “Reserving Client Classes in DHCPv4†and Section 8.3.5, “Reserving Client Classes in DHCPv6â€.

12.3. Using Vendor Class Information In Classification

The server checks whether an incoming DHCPv4 packet includes the vendor class identifier option (60) or an incoming DHCPv6 packet includes the vendor class option (16). If it does, the content of that option is prepended with "VENDOR_CLASS_" and the result is interpreted as a class. For example, modern cable modems will send this option with value "docsis3.0" and so the packet will belong to class "VENDOR_CLASS_docsis3.0".

12.4. Using Expressions In Classification

The expression portion of classification contains operators and values. All values are currently strings and operators take a string or strings and return another string. When all the operations have completed the result should be a value of "true" or "false". The packet belongs to the class (and the class name is added to the list of classes) if the result is "true". Expressions are written in standard format and can be nested.

Expressions are pre-processed during the parsing of the configuration file and converted to an internal representation. This allows certain types of errors to be caught and logged during parsing. Examples of these errors include an incorrect number or types of arguments to an operator. The evaluation code will also check for this class of error and generally throw an exception, though this should not occur in a normally functioning system.

Other issues, for example the starting position of a substring being outside of the substring or an option not existing in the packet, result in the operator returning an empty string.

Expressions are a work in progress and the supported operators and values are limited. The expectation is that additional operators and values will be added over time, however the basic mechanisms will remain the same.

Table 12.1. List of Classification Values

NameExample expressionExample valueDescription
String literal'example''example'A string
Hexadecimal string literal0x5a7d'Z}'A hexadecimal string
IP address literal10.0.0.10x0a000001An IP address
Integer literal123'123'A 32 bit unsigned integer value
Binary content of the optionoption[123].hex'(content of the option)'The value of the option with given code from the packet as hex
Option existenceoption[123].exists'true'If the option with given code is present in the packet "true" else "false"
DHCPv4 relay agent sub-optionrelay4[123].hex'(content of the RAI sub-option)'The value of sub-option with given code from the DHCPv4 Relay Agent Information option (option 82)
DHCPv6 Relay Optionsrelay6[nest].option[code].hex(value of the option)The value of the option with code "code" from the relay encapsulation "nest"
DHCPv6 Relay Peer Addressrelay6[nest].peeraddr2001:DB8::1The value of the peer address field from the relay encapsulation "nest"
DHCPv6 Relay Link Addressrelay6[nest].linkaddr2001:DB8::1The value of the link address field from the relay encapsulation "nest"
Interface name of packetpkt.ifaceeth0The name of the incoming interface of a DHCP packet.
Source address of packetpkt.src10.1.2.3The IP source address of a DHCP packet.
Destination address of packetpkt.dst10.1.2.3The IP destination address of a DHCP packet.
Length of packetpkt.len513The length of a DHCP packet (UDP header field), expressed as a 32 bit unsigned integer.
Hardware address in DHCPv4 packetpkt4.mac0x010203040506The value of the chaddr field of the DHCPv4 packet, hlen (0 to 16) bytes
Hardware length in DHCPv4 packetpkt4.hlen6The value of the hlen field of the DHCPv4 packet padded to 4 bytes
Hardware type in DHCPv4 packetpkt4.htype6The value of the htype field of the DHCPv4 packet padded to 4 bytes
ciaddr field in DHCPv4 packetpkt4.ciaddr192.0.2.1The value of the ciaddr field of the DHCPv4 packet (IPv4 address, 4 bytes)
giaddr field in DHCPv4 packetpkt4.giaddr192.0.2.1The value of the giaddr field of the DHCPv4 packet (IPv4 address, 4 bytes)
yiaddr field in DHCPv4 packetpkt4.yiaddr192.0.2.1The value of the yiaddr field of the DHCPv4 packet (IPv4 address, 4 bytes)
siaddr field in DHCPv4 packetpkt4.siaddr192.0.2.1The value of the siaddr field of the DHCPv4 packet (IPv4 address, 4 bytes)
Message Type in DHCPv4 packetpkt4.msgtype1The value of the message type field in the DHCPv4 packet (expressed as a 32 bit unsigned integer).
Transaction ID (xid) in DHCPv4 packetpkt4.transid12345The value of the transaction id in the DHCPv4 packet (expressed as a 32 bit unsigned integer).
Message Type in DHCPv6 packetpkt6.msgtype1The value of the message type field in the DHCPv6 packet (expressed as a 32 bit unsigned integer).
Transaction ID in DHCPv6 packetpkt6.transid12345The value of the transaction id in the DHCPv6 packet (expressed as a 32 bit unsigned integer).
Vendor option existence (any vendor)vendor[*].existstrueReturns whether a vendor option from any vendor is present ('true') or absent ('false').
Vendor option existence (specific vendor)vendor[4491].existstrueReturns whether a vendor option from specified vendor (determined by its enterprise-id) is present ('true') or absent ('false').
Enterprise-id from vendor optionvendor.enterprise4491If the vendor option is present, it returns the value of the enterprise-id field padded to 4 bytes. Returns "" otherwise.
Vendor sub-option existencevendor[4491].option[1].existstrueReturns 'true' if there is vendor option with specified enterprise-id and given sub-option is present. Returns 'false' otherwise.
Vendor sub-option contentvendor[4491].option[1].hexdocsis3.0Returns content of the specified sub-option of a vendor option with specified enterprise id. Returns '' if no such option or sub-option is present.
Vendor class option existence (any vendor)vendor-class[*].existstrueReturns whether a vendor class option from any vendor is present ('true') or absent ('false').
Vendor class option existence (specific vendor)vendor-class[4491].existstrueReturns whether a vendor class option from specified vendor (determined by its enterprise-id) is present ('true') or absent ('false').
Enterprise-id from vendor class optionvendor-class.enterprise4491If the vendor option is present, it returns the value of the enterprise-id field padded to 4 bytes. Returns "" otherwise.
First data chunk from vendor class optionvendor-class[4491].datadocsis3.0Returns content of the first data chunk from the vendor class option with specified enterprise-id. Returns "" if missing.
Specific data chunk from vendor class optionvendor-class[4491].data[3]docsis3.0Returns content of the specified data chunk of a vendor class option with specified enterprise id. Returns '' if no such option or data chunk is present.


Notes:

  • Hexadecimal strings are converted into a string as expected. The starting "0X" or "0x" is removed and if the string is an odd number of characters a "0" is prepended to it.

  • IP addresses are converted into strings of length 4 or 16. IPv4, IPv6, and IPv4 embedded IPv6 (e.g., IPv4 mapped IPv6) addresses are supported.

  • Integers in an expression are converted to 32 bit unsigned integers and are represented as four-byte strings. For example 123 is represented as 0x0000007b. All expressions that return numeric values use 32-bit unsigned integers, even if the field in the packet is smaller. In general it is easier to use decimal notation to represent integers, but it is also possible to use hex notation. When using hex notation to represent an integer care should be taken to make sure the value is represented as 32 bits, e.g. use 0x00000001 instead of 0x1 or 0x01. Also, make sure the value is specified in network order, e.g. 1 is represented as 0x00000001.

  • "option[code].hex" extracts the value of the option with the code "code" from the incoming packet. If the packet doesn't contain the option, it returns the empty string. The string is presented as a byte string of the option payload without the type code or length fields.

  • "option[code].exists" checks if an option with the code "code" is present in the incoming packet. It can be used with empty options.

  • "relay4[code].hex" attempts to extract the value of the sub-option "code" from the option inserted as the DHCPv4 Relay Agent Information (82) option. If the packet doesn't contain a RAI option, or the RAI option doesn't contain the requested sub-option, the expression returns an empty string. The string is presented as a byte string of the option payload without the type code or length fields. This expression is allowed in DHCPv4 only.

  • "relay4" shares the same representation types as "option", for instance "relay4[code].exists" is supported.

  • "relay6[nest]" allows access to the encapsulations used by any DHCPv6 relays that forwarded the packet. The "nest" level specifies the relay from which to extract the information, with a value of 0 indicating the relay closest to the DHCPv6 server. If the requested encapsulation doesn't exist an empty string "" is returned. This expression is allowed in DHCPv6 only.

  • "relay6[nest].option[code]" shares the same representation types as "option", for instance "relay6[nest].option[code].exists" is supported.

  • Expressions starting with "pkt4" can be used only in DHCPv4. They allows access to DHCPv4 message fields.

  • "pkt6" refers to information from the client request. To access any information from an intermediate relay use "relay6". "pkt6.msgtype" and "pkt6.transid" output a 4 byte binary string for the message type or transaction id. For example the message type SOLICIT will be "0x00000001" or simply 1 as in "pkt6.msgtype == 1".

  • Vendor option means Vendor-Identifying Vendor-specific Information option in DHCPv4 (code 125, see Section 4 of RFC 3925) and Vendor-specific Information Option in DHCPv6 (code 17, defined in Section 22.17 of RFC 3315). Vendor class option means Vendor-Identifying Vendor Class Option in DHCPv4 (code 124, see Section 3 of RFC 3925) in DHCPv4 and Class Option in DHCPv6 (code 16, see Section 22.16 of RFC 3315). Vendor options may have sub-options that are referenced by their codes. Vendor class options do not have sub-options, but rather data chunks, which are referenced by index value. Index 0 means the first data chunk, Index 1 is for the second data chunk (if present), etc.

  • In the vendor and vendor-class constructs Asterisk (*) or 0 can be used to specify a wildcard enterprise-id value, i.e. it will match any enterprise-id value.

  • Vendor Class Identifier (option 60 in DHCPv4) can be accessed using option[60] expression.

  • RFC3925 and RFC3315 allow for multiple instances of vendor options to appear in a single message. The client classification code currently examines the first instance if more than one appear. For vendor.enterprise and vendor-class.enterprise expressions, the value from the first instance is returned. Please submit a feature request on Kea website if you need support for multiple instances.

Table 12.2. List of Classification Expressions

NameExampleDescription
Equal'foo' == 'bar'Compare the two values and return "true" or "false"
Notnot ('foo' == 'bar')Logical negation
And('foo' == 'bar') and ('bar' == 'foo')Logical and
Or('foo' == 'bar') or ('bar' == 'foo')Logical or
Substringsubstring('foobar',0,3)Return the requested substring
Concatconcat('foo','bar')Return the concatenation of the strings


12.4.1. Logical operators

The Not, And and Or logical operators are the common operators. Not has the highest precedence and Or the lowest. And and Or are (left) associative, parentheses around a logical expression can be used to enforce a specific grouping, for instance in "A and (B or C)" (without parentheses "A and B or C" means "(A and B) or C").

12.4.2. Substring

The substring operator "substring(value, start, length)" accepts both positive and negative values for the starting position and the length. For "start", a value of 0 is the first byte in the string while -1 is the last byte. If the starting point is outside of the original string an empty string is returned. "length" is the number of bytes to extract. A negative number means to count towards the beginning of the string but doesn't include the byte pointed to by "start". The special value "all" means to return all bytes from start to the end of the string. If length is longer than the remaining portion of the string then the entire remaining portion is returned. Some examples may be helpful:
        substring('foobar', 0, 6) == 'foobar'
        substring('foobar', 3, 3) == 'bar'
        substring('foobar', 3, all) == 'bar'
        substring('foobar', 1, 4) == 'ooba'
        substring('foobar', -5, 4) == 'ooba'
        substring('foobar', -1, -3) == 'oba'
        substring('foobar', 4, -2) == 'ob'
        substring('foobar', 10, 2) == ''
          

12.4.3. Concat

The concat function "concat(string1, string2)" returns the concatenation of its two arguments. For instance:
        concat('foo', 'bar') == 'foobar'
          

Note

The expression for each class is executed on each packet received. If the expressions are overly complex, the time taken to execute them may impact the performance of the server. If you need complex or time consuming expressions you should write a hook to perform the necessary work.

12.5. Configuring Classes

A class contains three items: a name, a test expression and option data. The name must exist and must be unique amongst all classes. The test expression and option data are optional.

The test expression is a string containing the logical expression used to determine membership in the class. The entire expression is in double quotes.

The option data is a list which defines any options that should be assigned to members of this class.

In the following example the class named "Client_foo" is defined. It is comprised of all clients whose client ids (option 61) start with the string "foo". Members of this class will be given 192.0.2.1 and 192.0.2.2 as their domain name servers.

"Dhcp4": {
    "client-classes": [
        {
            "name": "Client_foo",
            "test": "substring(option[61].hex,0,3) == 'foo'",
            "option-data": [
                {
                    "name": "domain-name-servers",
                    "code": 6,
                    "space": "dhcp4",
                    "csv-format": true,
                    "data": "192.0.2.1, 192.0.2.2"
                }
            ]
        },
        ...
    ],
    ...
}

This example shows a client class being defined for use by the DHCPv6 server. In it the class named "Client_enterprise" is defined. It is comprised of all clients who's client identifiers start with the given hex string (which would indicate a DUID based on an enterprise id of 0xAABBCCDD). Members of this class will be given an 2001:db8:0::1 and 2001:db8:2::1 as their domain name servers.

"Dhcp6": {
    "client-classes": [
        {
            "name": "Client_enterprise",
            "test": "substring(option[1].hex,0,6) == 0x0002AABBCCDD'",
            "option-data": [
                {
                    "name": "dns-servers",
                    "code": 23,
                    "space": "dhcp6",
                    "csv-format": true,
                    "data": "2001:db8:0::1, 2001:db8:2::1"
                }
            ]
        },
        ...
    ],
    ...
}

12.6. Configuring Subnets With Class Information

In certain cases it beneficial to restrict access to certain subnets only to clients that belong to a given class, using the "client-class" keyword when defining the subnet.

Let's assume that the server is connected to a network segment that uses the 192.0.2.0/24 prefix. The Administrator of that network has decided that addresses from range 192.0.2.10 to 192.0.2.20 are going to be managed by the DHCP4 server. Only clients belonging to client class Client_foo are allowed to use this subnet. Such a configuration can be achieved in the following way:

"Dhcp4": {
    "client-classes": [
        {
            "name": "Client_foo",
            "test": "substring(option[61].hex,0,3) == 'foo'",
            "option-data": [
                {
                    "name": "domain-name-servers",
                    "code": 6,
                    "space": "dhcp4",
                    "csv-format": true,
                    "data": "192.0.2.1, 192.0.2.2"
                }
            ]
        },
        ...
    ],
    "subnet4": [
        {
            "subnet": "192.0.2.0/24",
            "pools": [ { "pool": "192.0.2.10 - 192.0.2.20" } ],
            "client-class": "Client_foo"
        },
        ...
    ],,
    ...
}

The following example shows restricting access to a DHCPv6 subnet. This configuration will restrict use of the addresses 2001:db8:1::1 to 2001:db8:1::FFFF to members of the "Client_enterprise" class.

"Dhcp6": {
    "client-classes": [
        {
            "name": "Client_enterprise",
            "test": "substring(option[1].hex,0,6) == 0x0002AABBCCDD'",
            "option-data": [
                {
                    "name": "dns-servers",
                    "code": 23,
                    "space": "dhcp6",
                    "csv-format": true,
                    "data": "2001:db8:0::1, 2001:db8:2::1"
                }
            ]
        },
        ...
    ], 
    "subnet6": [
        {
            "subnet": "2001:db8:1::/64",
            "pools": [ { "pool": "2001:db8:1::-2001:db8:1::ffff" } ],
            "client-class": "Client_enterprise"
        }
    ],
    ...
}

12.7. Using Classes

Currently classes can be used for two functions. They can supply options to the members of the class and they can be used to choose a subnet from which an address will be assigned to the class member.

When supplying options, options defined as part of the class definition are considered "class globals". They will override any global options that may be defined and in turn will be overridden by any options defined for an individual subnet.

12.8. Classes and Hooks

You may use a hook to classify your packets. This may be useful if the expression would either be complex or time consuming and be easier or better to write as code. Once the hook has added the proper class name to the packet the rest of the classification system will work as normal in choosing a subnet and selecting options. For a description of hooks see Chapter 13, Hooks Libraries, for a description on configuring classes see Section 12.5, “Configuring Classes†and Section 12.6, “Configuring Subnets With Class Informationâ€.

12.9. Debugging Expressions

While you are constructing your classification expressions you may find it useful to enable logging see Chapter 17, Logging for a more complete description of the logging facility.

To enable the debug statements in the classifciaton system you will need to set the severity to "DEBUG" and the debug level to at least 55. The specific loggers are "kea-dhcp4.eval" and "kea-dhcp6.eval".

In order to understand the logging statements one must understand a bit about how expressions are evaluated, for a more complete description refer to the design document at http://kea.isc.org/wiki/KeaDesigns. In brief there are two structures used during the evaluation of an expression: a list of tokens which represent the expressions and a value stack which represents the values being manipulated.

The list of tokens is created when the configuration file is processed with most expressions and values being converted to a token. The list is organized in reverse Polish notation. During execution, the list will be traversed in order. As each token is executed it will be able to pop values from the top of the stack and eventually push its result on the top of the stack. Imagine the following expression:

       "test": "substring(option[61].hex,0,3) == 'foo'",
       

This will result in the following tokens:

       option, number (0), number (3), substring, text ('foo'), equals
       

In this example the first three tokens will simply push values onto the stack. The substring token will then remove those three values and compute a result that it places on the stack. The text option also places a value on the stack and finally the equals token removes the two tokens on the stack and places its result on the stack.

When debug logging is enabled, each time a token is evaluated it will emit a log message indicating the values of any objects that were popped off of the value stack and any objects that were pushed onto the value stack.

The values will be displayed as either text if the command is known to use text values or hexadecimal if the command either uses binary values or can manipulate either text or binary values. For expressions that pop multiple values off the stack, the values will be displayed in the order they were popped. For most expressions this won't matter but for the concat expression the values are displayed in reverse order from how they are written in the expression.

Let us assume that the following test has been entered into the configuration. This example skips most of the configuration to concentrate on the test.

       "test": "substring(option[61].hex,0,3) == 'foo'",
       

The logging might then resemble this:

       2016-05-19 13:35:04.163 DEBUG [kea.eval/44478] EVAL_DEBUG_OPTION Pushing option 61 with value 0x666F6F626172
       2016-05-19 13:35:04.164 DEBUG [kea.eval/44478] EVAL_DEBUG_STRING Pushing text string '0'
       2016-05-19 13:35:04.165 DEBUG [kea.eval/44478] EVAL_DEBUG_STRING Pushing text string '3'
       2016-05-19 13:35:04.166 DEBUG [kea.eval/44478] EVAL_DEBUG_SUBSTRING Popping length 3, start 0, string 0x666F6F626172 pushing result 0x666F6F
       2016-05-19 13:35:04.167 DEBUG [kea.eval/44478] EVAL_DEBUG_STRING Pushing text string 'foo'
       2016-05-19 13:35:04.168 DEBUG [kea.eval/44478] EVAL_DEBUG_EQUAL Popping 0x666F6F and 0x666F6F pushing result 'true'
       

Note

The debug logging may be quite verbose if you have a number of expressions to evaluate. It is intended as an aid in helping you create and debug your expressions. You should plan to disable debug logging when you have your expressions working correctly. You also may wish to include only one set of expressions at a time in the configuration file while debugging them in order to limit the log statements. For example when adding a new set of expressions you might find it more convenient to create a configuration file that only includes the new expressions until you have them working correctly and then add the new set to the main configuration file.

Chapter 13. Hooks Libraries

13.1. Introduction

Although Kea offers a lot of flexibility, there may be cases where its behavior needs customisation. To accommodate this possibility, Kea includes the idea of "Hooks". This feature lets Kea load one or more dynamically-linked libraries (known as "hooks libraries") and, at various points in its processing ("hook points"), call functions in them. Those functions perform whatever custom processing is required.

Hooks libraries are attached to individual Kea processes, not to Kea as a whole. This means (for example) that it is possible to associate one set of libraries with the DHCP4 server and a different set to the DHCP6 server.

Another point to note is that it is possible for a process to load multiple libraries. When processing reaches a hook point, Kea calls the hooks library functions attached to it. If multiple libraries have attached a function to a given hook point, Kea calls all of them, in the order in which the libraries are specified in the configuration file. The order may be important: consult the documentation of the libraries to see if this is the case.

The next section describes how to configure hooks libraries. If you are interested in writing your own hooks library, information can be found in the Kea Developer's Guide.

13.2. Configuring Hooks Libraries

The hooks libraries for a given process are configured using the hooks-libraries keyword in the configuration for that process. (Note that the word "hooks" is plural). The value of the keyword is an array of map structures, each structure corresponding to a hooks library. For example, to set up two hooks libraries for the DHCPv4 server, the configuration would be:

"Dhcp4": {
    :
    "hooks-libraries": [
        {
            "library": "/opt/charging.so"
        },
        {
            "library": "/opt/local/notification.so",
            "parameters": {
                "mail": "spam@example.com",
                "floor": 13,
                "debug": false,
                "users": [ "alice", "bob", "charlie" ],
                "languages": {
                    "french": "bonjour",
                    "klingon": "yl'el"
                }
            }
        }
    ]
    :
}

Note

This is a change to the syntax used in Kea 0.9.2 and earlier, where hooks-libraries was a list of strings, each string being the name of a library. The change was made in Kea 1.0 to facilitate the specification of library-specific parameters, a capability available in Kea 1.1.0 onwards.

Note

The library reloading behavior has changed in Kea 1.1. Libraries are reloaded, even if their list hasn't changed. Kea does that, because the parameters specified for the library (or the files those parameters point to) may have changed.

Libraries may have additional parameters. Those are not mandatory in the sense that there may be libraries that don't require them. However, for specific library there is often specific requirement for specify certain set of parameters. Please consult the documentation for your library for details. In the example above, the first library has no parameters. The second library has five parameters, specifying mail (string parameter), floor (integer parameter), debug (boolean parameter) and even lists (list of strings) and maps (containing strings). Nested parameters could be used if the library supports it. This topic is explained in detail in the Hooks Developer's Guide in the "Configuring Hooks Libraries" section.

Notes:

  • The full path to each library should be given.

  • As noted above, order may be important - consult the documentation for each library.

  • An empty list has the same effect as omitting the hooks-libraries configuration element all together.

    Note

    There is one case where this is not true: if Kea is running with a configuration that contains a hooks-libraries item, and that item is removed and the configuration reloaded, the removal will be ignored and the libraries remain loaded. As a workaround, instead of removing the hooks-libraries item, change it to an empty list. This will be fixed in a future version of Kea.

At the present time, only the kea-dhcp4 and kea-dhcp6 processes support hooks libraries.

13.3. Available Hooks Libraries

As described above, the hooks functionality provides a way to customize a Kea server without modifying the core code. ISC has chosen to take advantage of this feature to provide functions that may only be useful to a subset of Kea users. To this end ISC has created some hooks libraries; these discussed in the following sections.

Note

Some of these libraries will be available with the base code while others will be shared with organizations supporting development of Kea , possibly as a 'benefit' or 'thank you' for helping to sustain the larger Kea project. If you would like to get access to those libraries, please consider taking out a support contract: this includes professional support, advance security notifications, input into our roadmap planning, and many other benefits, while helping making Kea sustainable in the long term.

Currently the following libraries are available or planned from ISC:

Table 13.1. List of available hooks libraries

NameAvailabilitySinceDescription
user_chkKea sourcesKea 0.8Reads known users list from a file. Unknown users will be assigned a lease from the last subnet defined in the configuration file, e.g. to redirect them a captive portal. This demonstrates how an external source of information can be used to influence the Kea allocation engine. This hook is part of the Kea source code and is available in the src/hooks/dhcp/user_chk directory.
Forensic LoggingSupport customersKea 1.1.0This library provides hooks that record a detailed log of lease assignments and renewals into a set of log files. In many legal jurisdictions companies, especially ISPs, must record information about the addresses they have leased to DHCP clients. This library is designed to help with that requirement. If the information that it records is sufficient it may be used directly. If your jurisdiction requires that you save a different set of information, you may use it as a template or example and create your own custom logging hooks.
Lightweight 4over6Support customersAutumn 2016Lightweight 4over6 (RFC 7596) is a new IPv6 transition technology that provides IPv4 as a service in IPv6-only network. It assumes that dual-stack clients will get a regular IPv6 address and IPv6 prefix, but only a fraction of an IPv4 address. The fraction is specified as port-set, which is essentially a range of TCP and UDP ports a client can use. By doing the transition on the client side, this technology eliminates the need to deploy expensive Carrier Grade NATs within the operator's network. The problem on the DHCP side is the non-trivial logic behind it: each client needs to receive an unique set of lightweight 4over6 options (RFC 7598), that include the IPv4 address (shared among several clients), port-set (which is unique among clients sharing the same IPv4 address) and a number of additional parameters. This hooks library will generate values of those options dynamically, thus eliminating the need to manually configure values for each client separately.


ISC hopes to see more hooks libraries become available as time progresses, both developed internally and externally. Since this list may evolve dynamically, we decided to keep it on a wiki page, available at this link: http://kea.isc.org/wiki/Hooks. If you are a developer or are aware of any hooks libraries not listed there, please send a note to the kea-users or kea-dev mailing lists and someone will update it.

13.3.1. user_chk: Checking User Access

The user_chk library is the first hooks library published by ISC. It attempts to serve several purposes:

  • To assign "new" or "unregistered" users to a restricted subnet, while "known" or "registered" users are assigned to unrestricted subnets.

  • To allow DHCP response options or vendor option values to be customized based upon user identity.

  • To provide a real time record of the user registration activity which can be sampled by an external consumer.

  • To serve as a demonstration of various capabilities possible using the hooks interface.

Once loaded, the library allows segregating incomings requests into known and unknown clients. For known clients, the packets are processed mostly as usual, except it is possible to override certain options being sent. That can be done on a per host basis. Clients that are not on the known hosts list will be treated as unknown and will be assigned to the last subnet defined in the configuration file.

As an example of use, this behavior may be used to put unknown users into a separate subnet that leads to a walled garden, where they can only access a registration portal. Once they fill in necessary data, their details are added to the known clients file and they get a proper address after their device is restarted.

Note

This library was developed several years before the host reservation mechanism has become available. Currently host reservation is much more powerful and flexible, but nevertheless the user_chk capability to consult and external source of information about clients and alter Kea's behavior is useful and remains of educational value.

The library reads the /tmp/user_chk_registry.txt file while being loaded and each time an incoming packet is processed. The file is expected to have each line contain a self-contained JSON snippet which must have the following two entries:

  • type, whose value is "HW_ADDR" for IPv4 users or "DUID" for IPv6 users

  • id, whose value is either the hardware address or the DUID from the equest formatted as a string of hex digits, with or without ":" delimiters.

and may have the zero or more of the following entries:

  • bootfile whose value is the pathname of the desired file

  • tftp_server whose value is the hostname or IP address of the desired server

A sample user registry file is shown below:

{ "type" : "HW_ADDR", "id" : "0c:0e:0a:01:ff:04", "bootfile" : "/tmp/v4bootfile" }
{ "type" : "HW_ADDR", "id" : "0c:0e:0a:01:ff:06", "tftp_server" : "tftp.v4.example.com" }
{ "type" : "DUID", "id" : "00:01:00:01:19:ef:e6:3b:00:0c:01:02:03:04", "bootfile" : "/tmp/v6bootfile" }
{ "type" : "DUID", "id" : "00:01:00:01:19:ef:e6:3b:00:0c:01:02:03:06", "tftp_server" : "tftp.v6.example.com" }

As with any other hooks libraries provided by ISC, internals of the user_chk code are well documented. You can take a look at the Kea Developer's Guide section dedicated to the user_chk library that discusses how the code works internally. That, together with our general entries in Hooks Framework section should give you some pointers how to extend this library and perhaps even write your own from scratch.

13.3.2. Forensic Logging Hooks

This section describes the forensic log hooks library. This library povides hooks that record a detailed log of lease assignments and renewals into a set of log files. Currently this library is only available to ISC customers with a support contract.

In many legal jurisdictions companies, especially ISPs, must record information about the addresses they have leased to DHCP clients. This library is designed to help with that requirement. If the information that it records is sufficient it may be used directly. If your jurisdiction requires that you save a different set of information you may use it as a template or example and create your own custom logging hooks.

This logging is done as a set of hooks to allow it to be customized to any particular need. Modifying a hooks library is easier and safer than updating the core code. In addition by using the hooks features those users who don't need to log this information can leave it out and avoid any performance penalties.

13.3.2.1. Log File Naming

The names for the log files have the following form:

path/base-name.CCYYMMDD.txt

The "path" and "base-name" are supplied in the configuration as described below see Section 13.3.2.4, “Configuring the Forensic Log Hooksâ€. The next part of the name is the date the log file was started, with four digits for year, two digits for month and two digits for day. The file is rotated on a daily basis.

Note

When running Kea servers for both DHCPv4 and DHCPv6 the log names must be distinct. See the examples in Section 13.3.2.4, “Configuring the Forensic Log Hooksâ€.

13.3.2.2. DHCPv4 Log Entries

For DHCPv4 the library creates entries based on DHCPREQUEST messages and corresponding DHCPv4 leases intercepted by lease4_select (for new leases) and lease4_renew (for renewed leases) hooks.

An entry is a single string with no embedded end-of-line markers and has the following sections:

address duration device-id {client-info} {relay-info}

Where:

  • address - the leased IPv4 address given out and whether it was assigned or renewed.

  • duration - the lease lifetime expressed in days (if present), hours, minutes and seconds. A lease lifetime of 0xFFFFFFFF will be denoted with the text "infinite duration".

  • device-id - the client's hardware address shown as numerical type and hex digit string.

  • client-info - the DHCP client id option (61) if present, shown as a hex string.

  • relay-info - for relayed packets the giaddr and the RAI circuit id and remote id options (option 82 sub options 1 and 2) if present. The circuit id and remote id are presented as hex strings

For instance (line breaks added for readability, they would not be present in the log file).

Address: 192.2.1.100 has been renewed for 1 hrs 52 min 15 secs to a device with
hardware address: hwtype=1 08:00:2b:02:3f:4e, client-id: 17:34:e2:ff:09:92:54
connected via relay at address: 192.2.16.33, identified by circuit-id:
68:6f:77:64:79 and remote-id: 87:f6:79:77:ef

13.3.2.3. DHCPv6 Log Entries

For DHCPv6 the library creates entries based on lease management actions intercepted by the lease6_select (for new leases), lease6_renew (for renewed leases) and lease6_rebind (for rebound leases).

An entry is a single string with no embedded end-of-line markers and has the following sections:

address duration device-id {relay-info}*

Where:

  • address - the leased IPv6 address or prefix given out and whether it was assigned or renewed.

  • duration - the lease lifetime expressed in days (if present), hours, minutes and seconds. A lease lifetime of 0xFFFFFFFF will be denoted with the text "infinite duration".

  • device-id - the client's DUID and hardware address (if present).

  • relay-info - for relayed packets the content of relay agent messages, remote id and subscriber id options (x and xx) if present.

For instance (line breaks added for readability, they would not be present in the log file).

Address:2001:db8:1:: has been assigned for 0 hrs 11 mins 53 secs to a device with
DUID: 17:34:e2:ff:09:92:54 and hardware address: hwtype=1 08:00:2b:02:3f:4e
(from Raw Socket) connected via relay at address: fe80::abcd for client on
link address: 3001::1, hop count: 1, identified by remote-id:
01:02:03:04:0a:0b:0c:0d:0e:0f and subscriber-id: 1a:2b:3c:4d:5e:6f

13.3.2.4. Configuring the Forensic Log Hooks

To use this functionality the hook library must be included in the configuration of the desired DHCP server modules. The legal_log library is installed alongside the Kea libraries in [kea-install-dir]/lib where kea-install-dir is determined by the "--prefix" option of the configure script. It defaults to /usr/local. Assuming the default value then, configuring kea-dhcp4 to load the legal_log library could be done with the following Kea4 configuration:

"Dhcp4": { 
    "hooks-libraries": [
        {
            "library": "/usr/local/lib/libdhcp_legal_log.so",
            "parameters": {
                "path": "/var/kea/var",
                "base-name": "kea-forensic4"
            }
        },
        ...
    ] 
}

To configure it for kea-dhcp6, the commands are simply as shown below:

"Dhcp6": { 
    "hooks-libraries": [
        {
            "library": "/usr/local/lib/libdhcp_legal_log.so",
            "parameters": {
                "path": "/var/kea/var",
                "base-name": "kea-forensic6"
            }
        },
        ...
    ] 
}

Two Hook Library parameters are supported:

  • path - the directory in which the forensic file(s) will be written. The default value is [prefix]/kea/var. The directory must exist.

  • base-name - an arbitrary value which is used in conjunction with the current system date to form the current foresnic file name. It defaults to kea-legal.

Chapter 14. Statistics

14.1. Statistics Overview

Both Kea DHCP servers support statistics gathering. A working DHCP server encounters various events that can cause certain statistics to be collected. For example, a DHCPv4 server may receive a packet (pkt4-received statistic increases by one) that after parsing was identified as a DHCPDISCOVER (pkt4-discover-received). The Server processed it and decided to send a DHCPOFFER representing its answer (pkt4-offer-sent and pkt4-sent statistics increase by one). Such events happen frequently, so it is not uncommon for the statistics to have values in high thousands. They can serve as an easy and powerful tool for observing a server's and network's health. For example, if pkt4-received statistic stops growing, it means that the clients' packets are not reaching the server.

There are four types of statistics:

  • integer - this is the most common type. It is implemented as 64 bit integer (int64_t in C++), so it can hold any value between -2^63 to 2^63 -1.
  • floating point - this type is intended to store floating point precision. It is implemented as double C++ type.
  • duration - this type is intended for recording time periods. It uses boost::posix_time::time_duration type, which stores hours, minutes, seconds and microseconds.
  • string - this type is intended for recording statistics in textual form. It uses std::string C++ type.

During normal operation, DHCPv4 and DHCPv6 servers gather statistics. For a list of DHCPv4 and DHCPv6 statistics, see Section 7.7, “Statistics in the DHCPv4 Server†and Section 8.11, “Statistics in the DHCPv6 Serverâ€, respectively.

To extract data from the statistics module, the control channel can be used. See Chapter 15, Management API for details. It is possible to retrieve a single or all statistics, reset statistics (i.e. set to neutral value, typically zero) or even remove completely a single or all statistics. See section Section 14.3, “Commands for Manipulating Statistics†for a list of statistic oriented commands.

14.2. Statistics Lifecycle

It is useful to understand how the Statistics Manager module works. When the server starts operation, the manager is empty and does not have any statistics. When statistic-get-all is executed, an empty list is returned. Once the server performs an operation that causes a statistic to change, the related statistic will be created. In the general case, once a statistic is recorded even once, it is kept in the manager, until explicitly removed, by statistic-remove or statistic-remove-all being called or the server is shut down. Per subnet statistics are explicitly removed when reconfiguration takes place.

Statistics are considered run-time properties, so they are not retained after server restart.

Removing a statistic that is updated frequently makes little sense as it will be re-added when the server code next records that statistic. The statistic-remove and statistic-remove-all commands are intended to remove statistics that are not expected to be observed in the near future. For example, a misconfigured device in a network may cause clients to report duplicate addresses, so the server will report increasing values of pkt4-decline-received. Once the problem is found and the device is removed, the system administrator may want to remove the pkt4-decline-received statistic, so it won't be reported anymore. If a duplicate address is detected ever again, the server will add this statistic back.

14.3. Commands for Manipulating Statistics

There are several commands defined that can be used for accessing (-get), resetting to zero or neutral value (-reset) or even removing a statistic completely (-remove). The difference between reset and remove is somewhat subtle. The reset command sets the value of the statistic to zero or neutral value. After this operation, the statistic will have a value of 0 (integer), 0.0 (float), 0h0m0s0us (duration) or "" (string). When asked for, a statistic with the values mentioned will be returned. Remove removes a statistic completely, so the statistic will not be reported anymore. Please note that the server code may add it back if there's a reason to record it.

Note

The following sections describe commands that can be sent to the server: the examples are not fragments of a configuration file. For more information on sending commands to Kea, see Chapter 15, Management API.

14.3.1. statistic-get command

statistic-get command retrieves a single statistic. It takes a single string parameter called name that specifies the statistic name. An example command may look like this:

{
    "command": "statistic-get",
    "arguments": {
        "name": "pkt4-received"
    }
}

The server will respond with details of the requested statistic, with result set to 0 indicating success and the specified statistic as the value of "arguments" parameter. If the requested statistic is not found, the response will contain an empty map, i.e. only { } as argument, but the status code will still be set to success (0).

14.3.2. statistic-reset command

statistic-reset command sets the specified statistic to its neutral value: 0 for integer, 0.0 for float, 0h0m0s0us for time duration and "" for string type. It takes a single string parameter called name that specifies the statistic name. An example command may look like this:

{
    "command": "statistic-reset",
    "arguments": {
        "name": "pkt4-received"
    }
}

If the specific statistic is found and reset was successful, the server will respond with a status of 0, indicating success and an empty parameters field. If an error is encountered (e.g. requested statistic was not found), the server will return a status code of 1 (error) and the text field will contain the error description.

14.3.3. statistic-remove command

statistic-remove command attempts to delete a single statistic. It takes a single string parameter called name that specifies the statistic name. An example command may look like this:

{
    "command": "statistic-remove",
    "arguments": {
        "name": "pkt4-received"
    }
}

If the specific statistic is found and its removal was successful, the server will respond with a status of 0, indicating success and an empty parameters field. If an error is encountered (e.g. requested statistic was not found), the server will return a status code of 1 (error) and the text field will contain the error description.

14.3.4. statistic-get-all command

statistic-get-all command retrieves all statistics recorded. An example command may look like this:

{
    "command": "statistic-get-all",
    "arguments": { }
}

The server will respond with details of all recorded statistics, with result set to 0 indicating that it iterated over all statistics (even when the total number of statistics is zero).

14.3.5. statistic-reset-all command

statistic-reset command sets all statistics to their neutral values: 0 for integer, 0.0 for float, 0h0m0s0us for time duration and "" for string type. An example command may look like this:

{
    "command": "statistic-reset-all",
    "arguments": { }
}

If the operation is successful, the server will respond with a status of 0, indicating success and an empty parameters field. If an error is encountered, the server will return a status code of 1 (error) and the text field will contain the error description.

14.3.6. statistic-remove-all command

statistic-remove-all command attempts to delete all statistics. An example command may look like this:

{
    "command": "statistic-remove-all",
    "arguments": { }
}

If the removal of all statistics was successful, the server will respond with a status of 0, indicating success and an empty parameters field. If an error is encountered, the server will return a status code of 1 (error) and the text field will contain the error description.

Chapter 15. Management API

A classic approach to daemon configuration assumes that the server's configuration is stored in configuration files and, when the configuration is changed, the daemon is restarted. This approach has the significant disadvantage of introducing periods of downtime, when client traffic is not handled. Another risk is that if the new configuration is invalid for whatever reason, the server may refuse to start, which will further extend the downtime period until the issue is resolved.

To avoid such problems, both the DHCPv4 and DHCPv6 servers include support for a mechanism that allows on-line reconfiguration without requiring server shutdown. Both servers can be instructed to open control sockets, which is a communication channel. The server is able to receive commands on that channel, act on them and report back status. While the set of commands in Kea 1.1.0 is limited, the number is expected to grow over time.

Currently the only supported type of control channel is UNIX stream socket. For details how to configure it, see Section 7.8, “Management API for the DHCPv4 Server†and Section 8.12, “Management API for the DHCPv6 Serverâ€. It is likely that support for other control channel types will be added in the future.

15.1. Data Syntax

Communication over the control channel is conducted using JSON structures. If configured, Kea will open a socket and listen for incoming connections. A process connecting to this socket is expected to send JSON commands structured as follows:

{
    "command": "foo",
    "arguments": {
	"param1": "value1",
	"param2": "value2",
	...
    }
}

command is the name of command to execute and is mandatory. arguments is a map of parameters required to carry out the given command. The exact content and format of the map is command specific.

The server will process the incoming command and then send a response of the form:

{
    "result": 0|1,
    "text": "textual description",
    "arguments": {
	"argument1": "value1",
	"argument2": "value2",
	...
    }
}

result indicates the outcome of the command. A value of 0 means success while any non-zero value designates an error. Currently 1 is used as a generic error, but additional error codes may be added in the future. The text field typically appears when result is non-zero and contains a description of the error encountered, but it may also appear for successful results (that is command specific). arguments is a map of additional data values returned by the server which is specific to the command issued. The map is always present, even if it contains no data values.

15.2. Using the Control Channel

Kea does not currently provide a client for using the control channel. The primary reason for this is the expectation is that the entity using the control channel is typically an IPAM or similar network management/monitoring software which may have quite varied expectations regarding the client and is even likely to be written in languages different than C or C++. Therefore only examples are provided to show how one can take advantage of the API.

The easiest way is to use a tool called socat, a tool available from socat homepage, but it is also widely available in Linux and BSD distributions. Once Kea is started, one could connect to the control interface using the following command:

$ socat UNIX:/path/to/the/kea/socket -

where /path/to/the/kea/socket is the path specified in the Dhcp4/control-socket/socket-name parameter in the Kea configuration file. Text passed to socat will be sent to Kea and the responses received from Kea printed to standard output.

It is also easy to open UNIX socket programmatically. An example of such a simplistic client written in C is available in the Kea Developer's Guide, chapter Control Channel Overview, section Using Control Channel.

15.3. Commands Supported by Both the DHCPv4 and DHCPv6 Servers

15.3.1. leases-reclaim

leases-reclaim command instructs the server to reclaim all expired leases immediately. The command has the following JSON syntax:

{
    "command": "leases-reclaim",
    "arguments": {
        "remove": true
    }
}

The remove boolean parameter is mandatory and it indicates whether the reclaimed leases should be removed from the lease database (if true), or they should be left in the expired-reclaimed state (if false). The latter facilitates lease affinity, i.e. ability to re-assign expired lease to the same client which used this lease before. See Section 9.3, “Configuring Lease Affinity†for the details. Also, see Section 9.1, “Lease Reclamation†for the general information about the processing of expired leases (leases reclamation).

15.3.2. list-commands

The list-commands command retrieves a list of all commands supported by the server. It does not take any arguments. An example command may look like this:

{
    "command": "list-commands",
    "arguments": { }
}

The server will respond with a list of all supported commands. The arguments element will be a list of strings. Each string will convey one supported command.

15.3.3. shutdown

The shutdown command instructs the server to initiate its shutdown procedure. It is the equivalent of sending a SIGTERM signal to the process. This command does not take any arguments. An example command may look like this:

{
    "command": "shutdown",
    "arguments": { }
}

The server will respond with a confirmation that the shutdown procedure has been initiated.

Chapter 16. The libdhcp++ Library

libdhcp++ is a library written in C++ that handles many DHCP-related tasks, including:

  • DHCPv4 and DHCPv6 packets parsing, manipulation and assembly
  • Option parsing, manipulation and assembly
  • Network interface detection
  • Socket operations such as creation, data transmission and reception and socket closing.

While this library is currently used by Kea, it is designed to be a portable, universal library, useful for any kind of DHCP-related software.

16.1. Interface detection and Socket handling

Both the DHCPv4 and DHCPv6 components share network interface detection routines. Interface detection is currently supported on Linux, all BSD family (FreeBSD, NetBSD, OpenBSD), Mac OS X and Solaris 11 systems.

DHCPv4 requires special raw socket processing to send and receive packets from hosts that do not have IPv4 address assigned. Support for this operation is implemented on Linux, FreeBSD, NetBSD and OpenBSD. It is likely that DHCPv4 component will not work in certain cases on other systems.

Chapter 17. Logging

17.1. Logging Configuration

During its operation Kea may produce many messages. They differ in severity (some are more important than others) and source (some are produced by specific components, e.g. hooks). It is useful to understand which log messages are needed and which are not, and configure your logging appropriately. For example, debug level messages can be safely ignored in a typical deployment. They are, however, very useful when debugging a problem.

The logging system in Kea is configured through the Logging section in your configuration file. All daemons (e.g. DHCPv4 and DHCPv6 servers) will use the configuration in the Logging section to see what should be logged and to where. This allows for sharing identical logging configuration between daemons.

17.1.1. Loggers

Within Kea, a message is logged through an entity called a "logger". Different components log messages through different loggers, and each logger can be configured independently of one another. Some components, in particular the DHCP server processes, may use multiple loggers to log messages pertaining to different logical functions of the component. For example, the DHCPv4 server uses one logger for messages pertaining to packet reception and transmission, another logger for messages related to lease allocation and so on. Some of the libraries used by the Kea servers, e.g. libdhcpsrv, use their own loggers.

Users implementing hooks libraries (code attached to the server at runtime) are responsible for creating the loggers used by those libraries. Such loggers should have unique names, different from the logger names used by Kea. In this way the messages output by the hooks library can be distingued from messages issued by the core Kea code. Unique names also allow the loggers to be configured independently of loggers used by Kea. Whenever it makes sense, a hook library can use multiple loggers to log messages pertaining to different logical parts of the library.

In the Logging section of a configuration file you can specify the configuration for zero or more loggers (including loggers used by the proprietary hooks libraries). If there are no loggers specified, the code will use default values: these cause Kea to log messages of INFO severity or greater to standard output. There is also a small time window after Kea has been started, but has not yet read its configuration. Logging in this short period can be controlled using environment variables. For details, see Section 17.1.3, “Logging During Kea Startupâ€.

The three main elements of a logger configuration are: name (the component that is generating the messages), the severity (what to log), and the output_commands (where to log). There is also a debuglevel element, which is only relevant if debug-level logging has been selected.

17.1.1.1. name (string)

Each logger in the system has a name, the name being that of the component binary file using it to log messages. For instance, if you want to configure logging for the DHCPv4 server, you add an entry for a logger named “kea-dhcp4â€. This configuration will then be used by the loggers in the DHCPv4 server, and all the libraries used by it (unless a library defines its own logger and there is specific logger configuration that applies to that logger).

When tracking down an issue with the server's operation, use of DEBUG logging is required to obtain the verbose output needed for problems diagnosis. However, the high verbosity is likely to overwhelm the logging system in cases when the server is processing high volume traffic. To mitigate this problem, use can be made of the fact that Kea uses multiple loggers for different functional parts of the server and that each of these can be configured independently. If the user is reasonably confident that a problem originates in a specific function of the server, or that the problem is related to the specific type of operation, they may enable high verbosity only for the relevant logger, so limiting the debug messages to the required minimum.

The loggers are associated with a particular library or binary of Kea. However, each library or binary may (and usually does) include multiple loggers. For example, the DHCPv4 server binary contains separate loggers for: packet parsing, for dropped packets, for callouts etc.

The loggers form a hierarchy. For each program in Kea, there is a "root" logger, named after the program (e.g. the root logger for kea-dhcp (the DHCPv4 server) is named kea-dhcp4. All other loggers are children of this logger, and are named accordingly, e.g. the the allocation engine in the DHCPv4 server logs messages using a logger called kea-dhcp4.alloc-engine.

This relationship is important as each child logger derives its default configuration from its parent root logger. In the typical case, the root logger configuration is the only logging configuration specified in the configuration file and so applies to all loggers. If an entry is made for a given logger, any attributes specified override those of the root logger, whereas any not specified are inherited from it.

To illustrate this, suppose you are using the DHCPv4 server with the root logger “kea-dhcp4†logging at the INFO level. In order to enable DEBUG verbosity for the DHCPv4 packet drops, you must create configuration entry for the logger called “kea-dhcp4.bad-packets†and specify severity DEBUG for this logger. All other configuration parameters may be omited for this logger if the logger should use the default values specified in the root logger's configuration.

If there are multiple logger specifications in the configuration that might match a particular logger, the specification with the more specific logger name takes precedence. For example, if there are entries for both “kea-dhcp4†and “kea-dhcp4.dhcpsrvâ€, the DHCPv4 server — and all libraries it uses that are not dhcpsrv — will log messages according to the configuration in the first entry (“kea-dhcp4â€).

Currently defined loggers are:

  • kea-dhcp4 - the root logger for the DHCPv4 server. All components used by the DHCPv4 server inherit the settings from this logger.
  • kea-dhcp4.alloc-engine - used by the lease allocation engine, which is responsible for managing leases in the lease database, i.e. create, modify and remove DHCPv4 leases as a result of processing messages from the clients.
  • kea-dhcp4.bad-packets - used by the DHCPv4 server daemon for logging inbound client packets that were dropped or to which the server responded with a DHCPNAK. It allows administrators to configure a separate log output that contains only packet drop and reject entries.
  • kea-dhcp4.callouts - used to log messages pertaining to the callouts registration and execution for the particular hook point.
  • kea-dhcp4.commands - used to log messages relating to the handling of commands received by the the DHCPv4 server over the command channel.
  • kea-dhcp4.ddns - used by the DHCPv4 server to log messages related to the Client FQDN and Hostname option processing. It also includes log messages related to the relevant DNS updates.
  • kea-dhcp4.dhcp4 - used by the DHCPv4 server daemon to log basic operations.
  • kea-dhcp4.dhcpsrv - the base logger for the libdhcpsrv library.
  • kea-dhcp4.eval - used to log messages relating to the client classification expression evaluation code.
  • kea-dhcp4.hooks - used to log messages related to management of hooks libraries, e.g. registration and deregistration of the libraries, and to the initialization of the callouts execution for various hook points within the DHCPv4 server.
  • kea-dhcp4.hosts - used within the libdhcpsrv and it logs messages related to the management of the DHCPv4 host reservations, i.e. retrieval of the reservations and adding new reservations.
  • kea-dhcp4.leases - used by the DHCPv4 server to log messages related to the lease allocation. The messages include detailed information about the allocated or offered leases, errors during the lease allocation etc.
  • kea-dhcp4.options - used by the DHCPv4 server to log messages related to processing of the options in the DHCPv4 messages, i.e. parsing options, encoding options into on-wire format and packet classification using options contained in the received packets.
  • kea-dhcp4.packets - this logger is mostly used to log messages related to transmission of the DHCPv4 packets, i.e. packet reception and sending a response. Such messages include information about the source and destination IP addresses and interfaces used to transmit packets. The logger is also used to log messages related to subnet selection, as this selection is usually based on the IP addresses and/or interface names, which can be retrieved from the received packet, even before the DHCPv4 message carried in the packet is parsed.
  • kea-dhcp6 - the root logger for the DHCPv6 server. All components used by the DHCPv6 server inherit the settings from this logger if there is no specialized logger provided.
  • kea-dhcp6.alloc-engine - used used by the lease allocation engine, which is responsible for managing leases in the lease database, i.e. create, modify and remove DHCPv6 leases as a result of processing messages from the clients.
  • kea-dhcp6.bad-packets - used used by the DHCPv6 server daemon for logging inbound client packets that were dropped.
  • kea-dhcp6.callouts - used to log messages pertaining to the callouts registration and execution for the particular hook point.
  • kea-dhcp6.commands - used to log messages relating to the handling of commands received by the the DHCPv6 server over the command channel.
  • kea-dhcp6.ddns - this logger is used by the DHCPv6 server to log messages related to the Client FQDN option processing. It also includes log messages related to the relevant DNS updates.
  • kea-dhcp6.dhcp6 - used DHCPv6 server daemon to log basic operations.
  • kea-dhcp6.dhcpsrv - the base logger for the libdhcpsrv library.
  • kea-dhcp6.eval - used to log messages relating to the client classification expression evaluation code.
  • kea-dhcp6.hooks - this logger is used to log messages related to management of hooks libraries, e.g. registration and deregistration of the libraries, and to the initialization of the callouts execution for various hook points within the DHCPv6 server.
  • kea-dhcp6.hosts - used within the libdhcpsrv and it logs messages related to the management of the DHCPv6 host reservations, i.e. retrieval of the reservations and adding new reservations.
  • kea-dhcp6.leases - used by the DHCPv6 server to log messages related to the lease allocation. The messages include detailed information about the allocated or offered leases, errors during the lease allocation etc.
  • kea-dhcp6.options - used by the DHCPv6 server to log messages related to processing of the options in the DHCPv6 messages, i.e. parsing options, encoding options into on-wire format and packet classification using options contained in the received packets.
  • kea-dhcp6.packets - this logger is mostly used to log messages related to transmission of the DHCPv6 packets, i.e. packet reception and sending a response. Such messages include the information about the source and destination IP addresses and interfaces used to transmit packets. This logger is also used to log messages related to subnet selection, as this selection is usually based on the IP addresses and/or interface names, which can be retrieved from the received packet, even before the DHCPv6 message carried in the packet is parsed.
  • kea-dhcp-ddns - the root logger for the kea-dhcp-ddns daemon. All components used by this daemon inherit the settings from this logger if there is no specialized logger provided.
  • kea-dhcp-ddns.dhcpddns - the logger used by the kea-dhcp-ddns daemon for logging configuration and global event information. This logger does not specify logging settings for libraries used by the daemon.
  • kea-dhcp-ddns.dhcp-to-d2 - used by the kea-dhcp-ddns daemon for logging information about events dealing with receiving messages from the DHCP servers and adding them to the queue for processing.
  • kea-dhcp-ddns.d2-to-dns - used by the kea-dhcp-ddns daemon for logging information about events dealing with sending and receiving messages with the DNS servers.

Note that user-defined hook libraries should not use any of those loggers but should define new loggers with names that correspond to the libraries using them. Suppose that the user created the library called “libpacket-capture†to dump packets received and transmitted by the server to the file. The appropriate name for the logger could be kea-dhcp4.packet-capture. (Note that the hook library implementor only specifies the second part of this name, i.e. “packet-captureâ€. The first part is a root logger name and is prepended by the Kea logging system.) It is also important to note that since this new logger is a child of a root logger, it inherits the configuration from the root logger, something that can be overridden by an entry in the configuration file.

The list of loggers above excludes any loggers implemented in hooks libraries. Please consult the documentation for the libraries for the names of the loggers they define.

Additional loggers may be defined in future versions of Kea. The easiest way to find out the logger name is to configure all logging to go to a single destination and look for specific logger names. See Section 17.1.2, “Logging Message Format†for details.

17.1.1.2. severity (string)

This specifies the category of messages logged. Each message is logged with an associated severity which may be one of the following (in descending order of severity):

  • FATAL - associated with messages generated by a condition that is so serious that the server cannot continue executing.
  • ERROR- associated with messages generated by an error condition. The server will continue executing, but the results may not be as expected.
  • WARN - indicates an out of the ordinary condition. However, the server will continue executing normally.
  • INFO - an informational message marking some event.
  • DEBUG - messages produced for debugging purposes.

When the severity of a logger is set to one of these values, it will only log messages of that severity and above (e.g. setting the logging severity to INFO will log INFO, WARN, ERROR and FATAL messages). The severity may also be set to NONE, in which case all messages from that logger are inhibited.

Note

The keactrl tool, described in Chapter 6, Managing Kea with keactrl, can be configured to start the servers in the verbose mode. If this is the case, the settings of the logging severity in the configuration file will have no effect, i.e. the servers will use logging severity of DEBUG regardless of the logging settings specified in the configuration file. If you need to control severity via configuration file, please make sure that the kea_verbose value is set to "no" within the keactrl configuration.

17.1.1.3. debuglevel (integer)

When a logger's severity is set to DEBUG, this value specifies what level of debug messages should be printed. It ranges from 0 (least verbose) to 99 (most verbose). If severity for the logger is not DEBUG, this value is ignored.

17.1.1.4. output_options (list)

Each logger can have zero or more output_options. These specify where log messages are sent. These are explained in detail below.

17.1.1.4.1. output (string)

This value determines the type of output. There are several special values allowed here: stdout (messages are printed on standard output), stderr (messages are printed on stderr), syslog (messages are logged to syslog using default name, syslog:name (messages are logged to syslog using specified name). Any other value is interpreted as a filename to which messages should be written.

17.1.1.4.2. flush (true of false)

Flush buffers after each log message. Doing this will reduce performance but will ensure that if the program terminates abnormally, all messages up to the point of termination are output. The default is "true".

17.1.1.4.3. maxsize (integer)

Only relevant when destination is file, this is maximum file size of output files in bytes. When the maximum size is reached, the file is renamed and a new file opened. (For example, a ".1" is appended to the name — if a ".1" file exists, it is renamed ".2", etc.)

If this is set to 0 or omitted, no maximum file size is used.

Note

Due to a limitation of the underlying logging library (log4cplus), rolling over the log files (from ".1" to ".2", etc) may show odd results: There can be multiple small files at the timing of roll over. This can happen when multiple processes try to roll over the files simultaneously. Version 1.1.0 of log4cplus solved this problem, so if this version or later of log4cplus is used to build Kea, it should not happen. Even for older versions it is normally expected to happen rarely unless the log messages are produced very frequently by multiple different processes.

17.1.1.4.4. maxver (integer)

Maximum number of old log files to keep around when rolling the output file. Only relevant when output is “fileâ€.

17.1.1.5. Example Logger Configurations

In this example we want to set the global logging to write to the console using standard output.

"Logging": {
    "loggers": [
        {
            "name": "kea-dhcp4",
            "output_options": [
                {
                    "output": "stdout"
                }
            ],
            "severity": "WARN"
        }
    ]
} 

In this second example, we want to store debug log messages in a file that is at most 2MB and keep up to 8 copies of old logfiles. Once the logfile grows to 2MB, it will be renamed and a new file file be created.

"Logging": {
    "loggers": [
        {
            "name": "kea-dhcp6",
            "output_options": [
                {
                    "output": "/var/log/kea-debug.log",
                    "maxver": 8,
                    "maxsize": 204800,
                    "flush": true
                }
            ],
            "severity": "DEBUG",
            "debuglevel": 99
        }
   ]
}

17.1.2. Logging Message Format

Each message written to the configured logging destinations comprises a number of components that identify the origin of the message and, if the message indicates a problem, information about the problem that may be useful in fixing it.

Consider the message below logged to a file:

2014-04-11 12:58:01.005 INFO  [kea-dhcp4.dhcpsrv/27456]
    DHCPSRV_MEMFILE_DB opening memory file lease database: type=memfile universe=4

Note: the layout of messages written to the system logging file (syslog) may be slightly different. This message has been split across two lines here for display reasons; in the logging file, it will appear on one line.

The log message comprises a number of components:

2014-04-11 12:58:01.005

The date and time at which the message was generated.

INFO

The severity of the message.

[kea-dhcp4.dhcpsrv/27456]

The source of the message. This comprises two elements: the Kea process generating the message (in this case, kea-dhcp4) and the component within the program from which the message originated (dhcpsrv, which is the name of the common library used by DHCP server implementations). The number after the slash is a process id (pid).

DHCPSRV_MEMFILE_DB

The message identification. Every message in Kea has a unique identification, which can be used as an index into the Kea Messages Manual (http://kea.isc.org/docs/kea-messages.html) from which more information can be obtained.

opening memory file lease database: type=memfile universe=4

A brief description. Within this text, information relating to the condition that caused the message to be logged will be included. In this example, the information is logged that the in-memory lease database backend will be used to store DHCP leases.

17.1.3. Logging During Kea Startup

The logging configuration is specified in the configuration file. However, when Kea starts, the file is not read until some way into the initialization process. Prior to that, the logging settings are set to default values, although it is possible to modify some aspects of the settings by means of environment variables. Note that in the absence of any logging configuration in the configuration file, the settings of (possibly modified) default configuration will persist while the program is running.

The following environment variables can be used to control the behavior of logging during startup:

KEA_LOCKFILE_DIR

Specifies a directory where the logging system should create its lock file. If not specified, it is prefix/var/run/kea, where prefix defaults to /usr/local. This variable must not end with a slash. There is one special value: "none", which instructs Kea to not create lock file at all. This may cause issues if several processes log to the same file.

KEA_LOGGER_DESTINATION

Specifies logging output. There are several special values.

stdout

Log to standard output.

stderr

Log to standard error.

syslog[:fac]

Log via syslog. The optional fac (which is separated from the word "syslog" by a colon) specifies the facility to be used for the log messages. Unless specified, messages will be logged using the facility "local0".

Any other value is treated as a name of the output file. If not specified otherwise, Kea will log to standard output.

Chapter 18. Frequently Asked Questions

This chapter contains a number of frequently asked questions and troubleshooting tips. It currently lacks content, but it is expected to grow over time.

18.1. General Frequently Asked Questions

18.1.1. Where did the Kea name came from?

Kea is the name of a high mountain parrot living in New Zealand. See this https://lists.isc.org/pipermail/kea-users/2014-October/000032.html for an extended answer.

18.1.2. Feature X is not supported yet. When/if will it be available?

Kea is developed by a small team of engineers. Our resources are limited, so we need to prioritize requests. The complexity of a new feature (how difficult it is to implement a feature and how likely it would break something that already works), amount of work required and expected popularity (i.e., how many users would actually benefit from it) are three leading factors. We sometimes also have contractual obligations.

Simply stating that you'd like feature X is useful. We try to implement features that are actively requested first, but the reality is that we have more requests than we can handle, so some of them must be postponed, at least in the near future. So is your request likely to be rejected? Not at all. You can do many things to greatly improve the chances of your request being fulfilled. First, it helps to explain why you need a feature. If your explanation is reasonable and there are likely other users that would benefit from it, the chances for Kea developers to put this task on a roadmap is better. Saying that you are willing to participate in tests (e.g., test engineering drops when they become available) is also helpful.

Another thing you can do to greatly improve the chances of a feature to appear is to actually develop it on your own and submit a patch. That's an avenue that people often forget about. Kea is open source software and we do accept patches. There are certain requirements, like code quality, comments, unit-tests, documentation, etc., but we have accepted a significant number of patches in the past, so it's doable. Accepted contributions range from minor documentation corrections to significant new features, like support for a new database type. Before considering writing and submitting a patch, make sure you read the Contributor's Guide in the Kea Developer's Guide.

Kea is developed by ISC, which is a non-profit organization. You may consider signing a development contract with us. In the past we did implement certain features due to contractual obligations. With additional funds we are able to put extra engineering efforts into Kea development. We can reshuffle our schedule or add extra hands to the team if needed. Please keep in mind that Kea is open source software and its principle goal is to provide a good DHCP solution that can be used by everyone. In other words, we may refuse a contract that would tie the solution to specific proprietary technology or make it unusable for other users. Also, we strive to make Kea a reference implementation, so if your proposal significantly violates a RFC, we may have a problem with that. Nevertheless, please talk to us and we may be able to find a solution.

Finally, Kea has a public roadmap, with releases happening several times each year. We tend to not modify plans for the current milestone, unless there are very good reasons to do so. Therefore "I'd like a feature X in 6 months" is much better received than "I'd like a feature X now".

18.2. Frequently Asked Questions about DHCPv4

18.2.1. I set up a firewall, but the Kea server still receives the traffic. Why?

Any DHCPv4 server must be able to receive from and send traffic to hosts that don't have an IPv4 address assigned yet. That is typically not possible with regular UDP sockets, therefore the Kea DHCPv4 server uses raw sockets by default. Raw sockets mean that the incoming packets are received as raw Ethernet frames, thus bypassing the whole kernel IP stack, including any firewalling rules your kernel may provide.

If you do not want the server to use raw sockets, it is possible to configure the Kea DHCPv4 server to use UDP sockets instead. See dhcp-socket-type described in Section 7.2.4, “Interface Configurationâ€. However, using UDP sockets has certain limitations. In particular, they may not allow for sending responses directly to clients without IPv4 addresses assigned. That's ok, if all your traffic is coming through relay agents.

18.3. Frequently Asked Questions about DHCPv6

18.3.1. Kea DHCPv6 doesn't seem to get incoming traffic. I checked with tcpdump (or other traffic capture software) that the incoming traffic is reaching the box. What's wrong?

Please check whether your OS has any IPv6 filtering rules. Many operating systems are shipped with firewalls that discard incoming IPv6 traffic by default. In particular, many Linux distributions do that. Please check the output of the following command:

# ip6tables -L -n

One common mistake in this area is to use iptables tool, which lists IPv4 firewall rules only.

Chapter 19. Acknowledgments

Kea is primarily designed, developed, and maintained by Internet Systems Consortium, Inc. It is an open source project and contributions are welcomed.

Support for the development of the DHCPv4, DHCPv6 and DHCP-DDNS components was provided by Comcast.

Kea was initially implemented as a collection of applications within the BIND 10 framework. Hence, Kea development would not be possible without the generous support of past BIND 10 project sponsors.

JPRS and CIRA were Patron Level BIND 10 sponsors.

AFNIC, CNNIC, CZ.NIC, DENIC eG, Google, RIPE NCC, Registro.br, .nz Registry Services, and Technical Center of Internet were past BIND 10 sponsors.

Afilias, IIS.SE, Nominet, and SIDN were founding sponsors of the BIND 10 project.

kea-1.1.0/doc/guide/install.xml0000664000175000017500000005442212772445242013246 00000000000000 ]> Installation
Packages Some operating systems or software package vendors may provide ready-to-use, pre-built software packages for Kea. Installing a pre-built package means you do not need to install the software required only to build Kea and do not need to make the software. FreeBSD ports, NetBSD pkgsrc, and Debian testing package collections provide all the prerequisite packages.
Installation Hierarchy The following is the directory layout of the complete Kea installation. (All directory paths are relative to the installation directory): bin/ — utility programs. etc/kea/ — configuration files. include/ — C++ development header files. lib/ — libraries. sbin/ — server software and commands used by the system administrator. share/kea/ — configuration specifications and examples. share/doc/kea/ — this guide, other supplementary documentation, and examples. share/man/ — manual pages (online documentation). var/kea/ — server identification, lease databases, and log files.
Building Requirements In addition to the run-time requirements (listed in ), building Kea from source code requires various development include headers and program development tools. Some operating systems have split their distribution packages into a run-time and a development package. You will need to install the development package versions, which include header files and libraries, to build Kea from the source code. Building from source code requires the following software installed on the system: Boost build-time headers (). At least Boost version 1.41 is required. When header-only Boost error code is not available or wanted, the Boost system library is required too. Botan (version 1.8, 1.9 or 1.10) or OpenSSL (versions 1.0.*). log4cplus (at least version 1.0.3) development include headers. A C++ compiler and standard development headers. Kea 1.1.0 builds have been tested with GCC g++ 4.2.1, 4.4.7, 4.6.3, 4.8.3, 4.8.4, 4.8.5, 5.4.0; Clang++ 3.4.1; and Apple Clang++ 703.0.31. The development tools automake, libtool, pkg-config. The MySQL client and the client development libraries, when using the --with-dhcp-mysql configuration flag to build the Kea MySQL database backend. In this case an instance of the MySQL server running locally or on a machine reachable over a network is required. Note that running the unit tests requires a local MySQL server. The PostgreSQL client and the client development libraries, when using the --with-dhcp-pgsql configuration flag to build the Kea PostgreSQL database backend. In this case an instance of the PostgreSQL server running locally or on some other machine, reachable over the network from the machine running Kea, is required. Note that running the unit tests requires a local PostgreSQL server. googletest (version 1.6 or later), when using the --with-gtest configuration option to build the unit tests. The documentation generation tools elinks, docbook-xsl, libxslt and Doxygen, if using the --enable-generate-docs configuration option to create the documentation. Visit the user-contributed wiki at for system-specific installation tips.
Installation from Source Kea is open source software written in C++. It is freely available in source code form from ISC as a downloadable tar file. A copy of the Kea source code repository is accessible from Github (). Kea may also be available in pre-compiled ready-to-use packages from operating system vendors.
Download Tar File The Kea release tarballs may be downloaded from: (using FTP or HTTP).
Retrieve from Git Downloading this "bleeding edge" code is recommended only for developers or advanced users. Using development code in a production environment is not recommended. When building from source code retrieved via Git, additional software will be required: automake (v1.11 or later), libtoolize, and autoconf (v2.59 or later). These may need to be installed. The latest development code is available on Github (see ). The Kea source is public and development is done in the master branch. The code can be checked out from https://github.com/isc-projects/kea.git: $ git clone https://github.com/isc-projects/kea.git The code checked out from the git repository does not include the generated configure script, Makefile.in files, nor their related build files. They can be created by running autoreconf with the switch. This will run autoconf, aclocal, libtoolize, autoheader, automake, and related commands. Write access to the Kea repository is only granted to ISC staff. If you are a developer planning to contribute to Kea, please fork our Github repository and use the "pull request" mechanism to request integration of your code. Please consult for help on how to fork a Github repository. The Kea Developer's Guide contains more information about the process, as well as describing the requirements for contributed code to be accepted by ISC.
Configure Before the Build Kea uses the GNU Build System to discover build environment details. To generate the makefiles using the defaults, simply run: $ ./configure Run ./configure with the switch to view the different options. Some commonly-used options are: --prefix Define the installation location (the default is /usr/local). --with-boost-include Define the path to find the Boost headers. --with-botan-config Specify the path to the botan-config script to build with Botan for cryptographic functions. --with-dhcp-mysql Build Kea with code to allow it to store leases (and access host reservations) in a MySQL database. --with-dhcp-pgsql Build Kea with code to allow it to store leases (and access host reservations) in a PostgreSQL database. --with-gtest-source Enable the building of the C++ Unit Tests using the Google Test framework. This option specifies the path to the gtest source. (If the framework is not installed on your system, it can be downloaded from .) --with-log4cplus Define the path to find the Log4cplus headers and libraries. --with-openssl Replace Botan by the OpenSSL the cryptographic library. By default configure searches for a valid Botan installation: if one is not found, it searches for OpenSSL. For instructions concerning the installation and configuration of database backends for Kea, see . For information concerning the configuration backends, see . For example, the following command configures Kea to find the Boost headers in /usr/pkg/include, specifies that PostgreSQL support should be enabled, and sets the installation location to /opt/kea: $ ./configure \ --with-boost-include=/usr/pkg/include \ --with-dhcp-pgsql=/usr/local/bin/pg_config \ --prefix=/opt/kea If you have some problems with building Kea using the header-only Boost code or you'd like to use the Boost system library (assumed for the sake of this example to be located in /usr/pkg/lib): $ ./configure \ --with-boost-libs=-lboost_system \ --with-boost-lib-dir=/usr/pkg/lib If configure fails, it may be due to missing or old dependencies. If configure succeeds, it displays a report with the parameters used to build the code. This report is saved into the file config.report and is also embedded into the executable binaries, e.g., kea-dhcp4.
Build After the configure step is complete, build the executables from the C++ code and prepare the Python scripts by running the command: $ make
Install To install the Kea executables, support files, and documentation, issue the command: $ make install Do not use any form of parallel or job server options (such as GNU make's -j option) when performing this step: doing so may cause errors. The install step may require superuser privileges. If required, run ldconfig as root with /usr/local/lib (or with prefix/lib if configured with --prefix) in /etc/ld.so.conf (or the relevant linker cache configuration file for your OS): $ ldconfig If you do not run ldconfig where it is required, you may see errors like the following: program: error while loading shared libraries: libkea-something.so.1: cannot open shared object file: No such file or directory
Selecting the Configuration Backend Kea 0.9 introduced configuration backends that are switchable during the compilation phase. Only one backend, JSON, is currently supported. JSON JSON is the new default configuration backend that allows Kea to read JSON configuration files from disk. It does not require any framework and thus is considered more lightweight. It will allow dynamic on-line reconfiguration, but lacks remote capabilities (i.e. no RESTful API).
DHCP Database Installation and Configuration Kea stores its leases in a lease database. The software has been written in a way that makes it possible to choose which database product should be used to store the lease information. At present, Kea supports four database backends: MySQL, PostgreSQL, Cassandra and Memfile. To limit external dependencies, MySQL, PostgreSQL and Cassandra support are disabled by default and only Memfile is available. Support for the optional external database backend must be explicitly included when Kea is built. This section covers the building of Kea with one of the optional backends and the creation of the lease database. When unit tests are built with Kea (the --with-gtest configuration option is specified), the databases must be manually pre-configured for the unit tests to run. The details of this configuration can be found in the Kea Developer's Guide.
Building with MySQL Support Install MySQL according to the instructions for your system. The client development libraries must be installed. Build and install Kea as described in , with the following modification. To enable the MySQL database code, at the "configure" step (see ), the --with-dhcp-mysql switch should be specified: ./configure [other-options] --with-dhcp-mysql If MySQL was not installed in the default location, the location of the MySQL configuration program "mysql_config" should be included with the switch, i.e. ./configure [other-options] --with-dhcp-mysql=path-to-mysql_config See for details regarding MySQL database configuration.
Building with PostgreSQL support Install PostgreSQL according to the instructions for your system. The client development libraries must be installed. Client development libraries are often packaged as "libpq". Build and install Kea as described in , with the following modification. To enable the PostgreSQL database code, at the "configure" step (see ), the --with-dhcp-pgsql switch should be specified: ./configure [other-options] --with-dhcp-pgsql If PostgreSQL was not installed in the default location, the location of the PostgreSQL configuration program "pg_config" should be included with the switch, i.e. ./configure [other-options] --with-dhcp-pgsql=path-to-pg_config See for details regarding PostgreSQL database configuration.
Building with CQL (Cassandra) support Install Cassandra according to the instructions for your system. The Cassandra project website contains useful pointers: . Download and compile cpp-driver from DataStax. For details regarding dependencies for building cpp-driver, see the project homepage . In June 2016, the following commands were used: $ git clone https://github.com/datastax/cpp-driver $ cd cpp-driver $ mkdir build $ cmake .. $ make As of June 2016, cpp-driver does not include cql_config script yet. Work is in progress to contribute such a script to the cpp-driver project but, until that is complete, intermediate steps that need to be conducted. A cql_config script is present in the tools/ directory of the Kea sources. Before using it, please edit cql_config_defines.sh in the same directory and change the environment variable CPP_DRIVER_PATH to point to the directory, where cpp-driver sources are located. (If the cpp-driver sources already provide cql_config script please use that rather than the version from Kea sources.) Build and install Kea as described in , with the following modification. To enable the Cassandra (CQL) database code, at the "configure" step (see ), do: ./configure [other-options] --with-cql=path-to-cql_config
kea-1.1.0/doc/guide/dhcp4-srv.xml0000664000175000017500000052170012772445242013410 00000000000000 ]> The DHCPv4 Server
Starting and Stopping the DHCPv4 Server It is recommended that the Kea DHCPv4 server be started and stopped using keactrl (described in ). However, it is also possible to run the server directly: it accepts the following command-line switches: -c file - specifies the configuration file. This is the only mandatory switch. -d - specifies whether the server logging should be switched to debug/verbose mode. In verbose mode, the logging severity and debuglevel specified in the configuration file are ignored and "debug" severity and the maximum debuglevel (99) are assumed. The flag is convenient, for temporarily switching the server into maximum verbosity, e.g. when debugging. -p port - specifies UDP port on which the server will listen. This is only useful during testing, as a DHCPv4 server listening on ports other than the standard ones will not be able to handle regular DHCPv4 queries. -v - prints out the Kea version and exits. -V - prints out the Kea extended version with additional parameters and exits. The listing includes the versions of the libraries dynamically linked to Kea. -W - prints out the Kea configuration report and exits. The report is a copy of the config.report file produced by ./configure: it is embedded in the executable binary. The config.report may also be accessed more directly. The following command may be used to extract this information. The binary path may be found in the install directory or in the .libs subdirectory in the source tree. For example kea/src/bin/dhcp4/.libs/kea-dhcp4. strings path/kea-dhcp4 | sed -n 's/;;;; //p' On start-up, the server will detect available network interfaces and will attempt to open UDP sockets on all interfaces mentioned in the configuration file. Since the DHCPv4 server opens privileged ports, it requires root access. Make sure you run this daemon as root. During startup the server will attempt to create a PID file of the form: localstatedir]/[conf name].kea-dhcp6.pid where: localstatedir: The value as passed into the build configure script. It defaults to "/usr/local/var". (Note that this value may be overridden at run time by setting the environment variable KEA_PIDFILE_DIR. This is intended primarily for testing purposes.) conf name: The configuration file name used to start the server, minus all preceding path and file extension. For example, given a pathname of "/usr/local/etc/kea/myconf.txt", the portion used would be "myconf". If the file already exists and contains the PID of a live process, the server will issue a DHCP4_ALREADY_RUNNING log message and exit. It is possible, though unlikely, that the file is a remnant of a system crash and the process to which the PID belongs is unrelated to Kea. In such a case it would be necessary to manually delete the PID file. The server can be stopped using the kill command. When running in a console, the server can also be shut down by pressing ctrl-c. It detects the key combination and shuts down gracefully.
DHCPv4 Server Configuration
Introduction This section explains how to configure the DHCPv4 server using the Kea configuration backend. (Kea configuration using any other backends is outside of scope of this document.) Before DHCPv4 is started, its configuration file has to be created. The basic configuration is as follows: { # DHCPv4 configuration starts in this line "Dhcp4": { # First we set up global values "valid-lifetime": 4000, "renew-timer": 1000, "rebind-timer": 2000, # Next we setup the interfaces to be used by the server. "interfaces-config": { "interfaces": [ "eth0" ] }, # And we specify the type of lease database "lease-database": { "type": "memfile", "persist": true, "name": "/var/kea/dhcp4.leases" }, # Finally, we list the subnets from which we will be leasing addresses. "subnet4": [ { "subnet": "192.0.2.0/24", "pools": [ { "pool": "192.0.2.1 - 192.0.2.200" } ] } ] # DHCPv4 configuration ends with the next line } } The following paragraphs provide a brief overview of the parameters in the above example together with their format. Subsequent sections of this chapter go into much greater detail for these and other parameters. The lines starting with a hash (#) are comments and are ignored by the server; they do not impact its operation in any way. The configuration starts in the first line with the initial opening curly bracket (or brace). Each configuration consists of one or more objects. In this specific example, we have only one object, called Dhcp4. This is a simplified configuration, as usually there will be additional objects, like Logging or DhcpDns, but we omit them now for clarity. The Dhcp4 configuration starts with the "Dhcp4": { line and ends with the corresponding closing brace (in the above example, the brace after the last comment). Everything defined between those lines is considered to be the Dhcp4 configuration. In the general case, the order in which those parameters appear does not matter. There are two caveats here though. The first one is to remember that the configuration file must be well formed JSON. That means that the parameters for any given scope must be separated by a comma and there must not be a comma after the last parameter. When reordering a configuration file, keep in mind that moving a parameter to or from the last position in a given scope may also require moving the comma. The second caveat is that it is uncommon — although legal JSON — to repeat the same parameter multiple times. If that happens, the last occurrence of a given parameter in a given scope is used while all previous instances are ignored. This is unlikely to cause any confusion as there are no real life reasons to keep multiple copies of the same parameter in your configuration file. Moving onto the DHCPv4 configuration elements, the first few elements define some global parameters. valid-lifetime defines for how long the addresses (leases) given out by the server are valid. If nothing changes, a client that got an address is allowed to use it for 4000 seconds. (Note that integer numbers are specified as is, without any quotes around them.) renew-timer and rebind-timer are values (also in seconds) that define T1 and T2 timers that govern when the client will begin the renewal and rebind procedures. Note that renew-timer and rebind-timer are optional. If they are not specified the client will select values for T1 and T2 timers according to the RFC 2131. The interfaces-config map specifies the server configuration concerning the network interfaces, on which the server should listen to the DHCP messages. The interfaces parameter specifies a list of network interfaces on which the server should listen. Lists are opened and closed with square brackets, with elements separated by commas. Had we wanted to listen on two interfaces, the interfaces-config would look like this: "interfaces-config": { "interfaces": [ "eth0", "eth1" ] }, The next couple of lines define the lease database, the place where the server stores its lease information. This particular example tells the server to use memfile, which is the simplest (and fastest) database backend. It uses an in-memory database and stores leases on disk in a CSV file. This is a very simple configuration. Usually the lease database configuration is more extensive and contains additional parameters. Note that lease-database is an object and opens up a new scope, using an opening brace. Its parameters (just one in this example - type) follow. Had there been more than one, they would be separated by commas. This scope is closed with a closing brace. As more parameters for the Dhcp4 definition follow, a trailing comma is present. Finally, we need to define a list of IPv4 subnets. This is the most important DHCPv4 configuration structure as the server uses that information to process clients' requests. It defines all subnets from which the server is expected to receive DHCP requests. The subnets are specified with the subnet4 parameter. It is a list, so it starts and ends with square brackets. Each subnet definition in the list has several attributes associated with it, so it is a structure and is opened and closed with braces. At a minimum, a subnet definition has to have at least two parameters: subnet (that defines the whole subnet) and pools (which is a list of dynamically allocated pools that are governed by the DHCP server). The example contains a single subnet. Had more than one been defined, additional elements in the subnet4 parameter would be specified and separated by commas. For example, to define three subnets, the following syntax would be used: "subnet4": [ { "pools": [ { "pool": "192.0.2.1 - 192.0.2.200" } ], "subnet": "192.0.2.0/24" }, { "pools": [ { "pool": "192.0.3.100 - 192.0.3.200" } ], "subnet": "192.0.3.0/24" }, { "pools": [ { "pool": "192.0.4.1 - 192.0.4.254" } ], "subnet": "192.0.4.0/24" } ] Note that indentation is optional and is used for aesthetic purposes only. In some cases in may be preferable to use more compact notation. After all the parameters have been specified, we have two contexts open: global and Dhcp4, hence we need two closing curly brackets to close them. In a real life configuration file there most likely would be additional components defined such as Logging or DhcpDdns, so the closing brace would be followed by a comma and another object definition.
Lease Storage All leases issued by the server are stored in the lease database. Currently there are four database backends available: memfile (which is the default backend), MySQL, PostgreSQL and Cassandra.
Memfile - Basic Storage for Leases The server is able to store lease data in different repositories. Larger deployments may elect to store leases in a database. describes this option. In typical smaller deployments though, the server will store lease information in a CSV file rather than a database. As well as requiring less administration, an advantage of using a file for storage is that it eliminates a dependency on third-party database software. The configuration of the file backend (Memfile) is controlled through the Dhcp4/lease-database parameters. The type parameter is mandatory and it specifies which storage for leases the server should use. The value of "memfile" indicates that the file should be used as the storage. The following list gives additional, optional, parameters that can be used to configure the Memfile backend. persist: controls whether the new leases and updates to existing leases are written to the file. It is strongly recommended that the value of this parameter is set to true at all times, during the server's normal operation. Not writing leases to disk will mean that if a server is restarted (e.g. after a power failure), it will not know what addresses have been assigned. As a result, it may hand out addresses to new clients that are already in use. The value of false is mostly useful for performance testing purposes. The default value of the persist parameter is true, which enables writing lease updates to the lease file. name: specifies an absolute location of the lease file in which new leases and lease updates will be recorded. The default value for this parameter is "[kea-install-dir]/var/kea/kea-leases4.csv" . lfc-interval: specifies the interval in seconds, at which the server will perform a lease file cleanup (LFC). This removes redundant (historical) information from the lease file and effectively reduces the lease file size. The cleanup process is described in more detailed fashion further in this section. The default value of the lfc-interval is 0, which disables the LFC. An example configuration of the Memfile backend is presented below: "Dhcp4": { "lease-database": { "type": "memfile", "persist": true, "name": "/tmp/kea-leases4.csv", "lfc-interval": 1800 } } This configuration selects the /tmp/kea-leases4.csv as the storage for lease information and enables persistence (writing lease updates to this file). It also configures the backend perform the periodic cleanup of the lease files, executed every 30 minutes. It is important to know how the lease file contents are organized to understand why the periodic lease file cleanup is needed. Every time the server updates a lease or creates a new lease for the client, the new lease information must be recorded in the lease file. For performance reasons, the server does not update the existing client's lease in the file, as it would potentially require rewriting the entire file. Instead, it simply appends the new lease information to the end of the file: the previous lease entries for the client are not removed. When the server loads leases from the lease file, e.g. at the server startup, it assumes that the latest lease entry for the client is the valid one. The previous entries are discarded. This means that the server can re-construct the accurate information about the leases even though there may be many lease entries for each client. However, storing many entries for each client results in bloated lease file and impairs the performance of the server's startup and reconfiguration as it needs to process a larger number of lease entries. Lease file cleanup (LFC) removes all previous entries for each client and leaves only the latest ones. The interval at which the cleanup is performed is configurable, and it should be selected according to the frequency of lease renewals initiated by the clients. The more frequent the renewals, the smaller the value of lfc-interval should be. Note however, that the LFC takes time and thus it is possible (although unlikely) that new cleanup is started while the previous cleanup instance is still running, if the lfc-interval is too short. The server would recover from this by skipping the new cleanup when it detects that the previous cleanup is still in progress. But it implies that the actual cleanups will be triggered more rarely than configured. Moreover, triggering a new cleanup adds an overhead to the server which will not be able to respond to new requests for a short period of time when the new cleanup process is spawned. Therefore, it is recommended that the lfc-interval value is selected in a way that would allow for the LFC to complete the cleanup before a new cleanup is triggered. Lease file cleanup is performed by a separate process (in background) to avoid a performance impact on the server process. In order to avoid the conflicts between two processes both using the same lease files, the LFC process operates on the copy of the original lease file, rather than on the lease file used by the server to record lease updates. There are also other files being created as a side effect of the lease file cleanup. The detailed description of the LFC is located on the Kea wiki: .
Lease Database Configuration Lease database access information must be configured for the DHCPv4 server, even if it has already been configured for the DHCPv6 server. The servers store their information independently, so each server can use a separate database or both servers can use the same database. Lease database configuration is controlled through the Dhcp4/lease-database parameters. The type of the database must be set to "memfile", "mysql", "postgresql" or "cql", e.g. "Dhcp4": { "lease-database": { "type": "mysql", ... }, ... } Next, the name of the database to hold the leases must be set: this is the name used when the database was created (see , or ). "Dhcp4": { "lease-database": { "name": "database-name" , ... }, ... } If the database is located on a different system to the DHCPv4 server, the database host name must also be specified. (It should be noted that this configuration may have a severe impact on server performance.): "Dhcp4": { "lease-database": { "host": remote-host-name, ... }, ... } The usual state of affairs will be to have the database on the same machine as the DHCPv4 server. In this case, set the value to the empty string: "Dhcp4": { "lease-database": { "host" : "", ... }, ... } Should the database be located on a different system, you may need to specify a longer interval for the connection timeout: "Dhcp4": { "lease-database": { "connect-timeout" : timeout-in-seconds, ... }, ... } The default value of five seconds should be more than adequate for local connections. If a timeout is given though, it should be an integer greater than zero. Finally, the credentials of the account under which the server will access the database should be set: "Dhcp4": { "lease-database": { "user": "user-name", "password": "password", ... }, ... } If there is no password to the account, set the password to the empty string "". (This is also the default.)
Hosts Storage Kea is also able to store information about host reservations in the database. The hosts database configuration uses the same syntax as the lease database. In fact, a Kea server opens independent connections for each purpose, be it lease or hosts information. This arrangement gives the most flexibility. Kea can be used to keep leases and host reservations separately, but can also point to the same database. Currently the supported hosts database types are MySQL and PostgreSQL. The Cassandra backend does not support host reservations yet. Please note that usage of hosts storage is optional. A user can define all host reservations in the configuration file. That is the recommended way if the number of reservations is small. However, when the number of reservations grows it's more convenient to use host storage. Please note that both storage methods (configuration file and one of the supported databases) can be used together. If hosts are defined in both places, the definitions from the configuration file are checked first and external storage is checked later, if necessary.
DHCPv4 Hosts Database Configuration Hosts database configuration is controlled through the Dhcp4/hosts-database parameters. If enabled, the type of the database must be set to "mysql" or "postgresql". Other hosts backends may be added in later versions of Kea. "Dhcp4": { "hosts-database": { "type": "mysql", ... }, ... } Next, the name of the database to hold the reservations must be set: this is the name used when the lease database was created (see for instructions how to setup the desired database type). "Dhcp4": { "hosts-database": { "name": "database-name" , ... }, ... } If the database is located on a different system than the DHCPv4 server, the database host name must also be specified. (Again it should be noted that this configuration may have a severe impact on server performance.): "Dhcp4": { "hosts-database": { "host": remote-host-name, ... }, ... } The usual state of affairs will be to have the database on the same machine as the DHCPv4 server. In this case, set the value to the empty string: "Dhcp4": { "hosts-database": { "host" : "", ... }, ... } Finally, the credentials of the account under which the server will access the database should be set: "Dhcp4": { "hosts-database": { "user": "user-name", "password": "password", ... }, ... } If there is no password to the account, set the password to the empty string "". (This is also the default.)
Using Read-Only Databases for Host Reservations In some deployments the database user whose name is specified in the database backend configuration may not have write privileges to the database. This is often required by the policy within a given network to secure the data from being unintentionally modified. In many cases administrators have inventory databases deployed, which contain substantially more information about the hosts than static reservations assigned to them. The inventory database can be used to create a view of a Kea hosts database and such view is often read only. Kea host database backends operate with an implicit configuration to both read from and write to the database. If the database user does not have write access to the host database, the backend will fail to start and the server will refuse to start (or reconfigure). However, if access to a read only host database is required for retrieving reservations for clients and/or assign specific addresses and options, it is possible to explicitly configure Kea to start in "read-only" mode. This is controlled by the readonly boolean parameter as follows: "Dhcp4": { "hosts-database": { "readonly": true, ... }, ... } Setting this parameter to false would configure the database backend to operate in "read-write" mode, which is also a default configuration if the parameter is not specified. The readonly parameter is currently only supported for MySQL and PostgreSQL databases.
Interface Configuration The DHCPv4 server has to be configured to listen on specific network interfaces. The simplest network interface configuration tells the server to listen on all available interfaces: "Dhcp4": { "interfaces-config": { "interfaces": [ "*" ] } ... }, The asterisk plays the role of a wildcard and means "listen on all interfaces". However, it is usually a good idea to explicitly specify interface names: "Dhcp4": { "interfaces-config": { "interfaces": [ "eth1", "eth3" ] }, ... } It is possible to use wildcard interface name (asterisk) concurrently with explicit interface names: "Dhcp4": { "interfaces-config": { "interfaces": [ "eth1", "eth3", "*" ] }, ... } It is anticipated that this form of usage will only be used when it is desired to temporarily override a list of interface names and listen on all interfaces. Some deployments of DHCP servers require that the servers listen on the interfaces with multiple IPv4 addresses configured. In these situations, the address to use can be selected by appending an IPv4 address to the interface name in the following manner: "Dhcp4": { "interfaces-config": { "interfaces": [ "eth1/10.0.0.1", "eth3/192.0.2.3" ] }, ... } Should the server be required to listen on multiple IPv4 addresses assigned to the same interface, multiple addresses can be specified for an interface as in the example below: "Dhcp4": { "interfaces-config": { "interfaces": [ "eth1/10.0.0.1", "eth1/10.0.0.2" ] }, ... } Alternatively, if the server should listen on all addresses for the particular interface, an interface name without any address should be specified. Kea supports responding to directly connected clients which don't have an address configured. This requires that the server injects the hardware address of the destination into the data link layer of the packet being sent to the client. The DHCPv4 server utilizes the raw sockets to achieve this, and builds the entire IP/UDP stack for the outgoing packets. The down side of raw socket use, however, is that incoming and outgoing packets bypass the firewalls (e.g. iptables). It is also troublesome to handle traffic on multiple IPv4 addresses assigned to the same interface, as raw sockets are bound to the interface and advanced packet filtering techniques (e.g. using the BPF) have to be used to receive unicast traffic on the desired addresses assigned to the interface, rather than capturing whole traffic reaching the interface to which the raw socket is bound. Therefore, in the deployments where the server doesn't have to provision the directly connected clients and only receives the unicast packets from the relay agents, the DHCP server should be configured to utilize IP/UDP datagram sockets instead of raw sockets. The following configuration demonstrates how this can be achieved: "Dhcp4": { "interfaces-config": { "interfaces": [ "eth1", "eth3" ], "dhcp-socket-type": "udp" }, ... } The dhcp-socket-type specifies that the IP/UDP sockets will be opened on all interfaces on which the server listens, i.e. "eth1" and "eth3" in our case. If the dhcp-socket-type is set to raw, it configures the server to use raw sockets instead. If the dhcp-socket-type value is not specified, the default value raw is used. Using UDP sockets automatically disables the reception of broadcast packets from directly connected clients. This effectively means that the UDP sockets can be used for relayed traffic only. When using the raw sockets, both the traffic from the directly connected clients and the relayed traffic will be handled. Caution should be taken when configuring the server to open multiple raw sockets on the interface with several IPv4 addresses assigned. If the directly connected client sends the message to the broadcast address all sockets on this link will receive this message and multiple responses will be sent to the client. Hence, the configuration with multiple IPv4 addresses assigned to the interface should not be used when the directly connected clients are operating on that link. To use a single address on such interface, the "interface-name/address" notation should be used. Specifying the value raw as the socket type, doesn't guarantee that the raw sockets will be used! The use of raw sockets to handle the traffic from the directly connected clients is currently supported on Linux and BSD systems only. If the raw sockets are not supported on the particular OS, the server will issue a warning and fall back to use IP/UDP sockets.
Issues with Unicast Responses to DHCPINFORM The use of UDP sockets has certain benefits in deployments where the server receives only relayed traffic; these benefits are mentioned in . From the administrator's perspective it is often desirable to configure the system's firewall to filter out the unwanted traffic, and the use of UDP sockets facilitates this. However, the administrator must also be aware of the implications related to filtering certain types of traffic as it may impair the DHCP server's operation. In this section we are focusing on the case when the server receives the DHCPINFORM message from the client via a relay. According to RFC 2131, the server should unicast the DHCPACK response to the address carried in the "ciaddr" field. When the UDP socket is in use, the DHCP server relies on the low level functions of an operating system to build the data link, IP and UDP layers of the outgoing message. Typically, the OS will first use ARP to obtain the client's link layer address to be inserted into the frame's header, if the address is not cached from a previous transaction that the client had with the server. When the ARP exchange is successful, the DHCP message can be unicast to the client, using the obtained address. Some system administrators block ARP messages in their network, which causes issues for the server when it responds to the DHCPINFORM messages, because the server is unable to send the DHCPACK if the preceding ARP communication fails. Since the OS is entirely responsible for the ARP communication and then sending the DHCP packet over the wire, the DHCP server has no means to determine that the ARP exchange failed and the DHCP response message was dropped. Thus, the server does not log any error messages when the outgoing DHCP response is dropped. At the same time, all hooks pertaining to the packet sending operation will be called, even though the message never reaches its destination. Note that the issue described in this section is not observed when the raw sockets are in use, because, in this case, the DHCP server builds all the layers of the outgoing message on its own and does not use ARP. Instead, it inserts the value carried in the 'chaddr' field of the DHCPINFORM message into the link layer. Server administrators willing to support DHCPINFORM messages via relays should not block ARP traffic in their networks or should use raw sockets instead of UDP sockets.
IPv4 Subnet Identifier The subnet identifier is a unique number associated with a particular subnet. In principle, it is used to associate clients' leases with their respective subnets. When a subnet identifier is not specified for a subnet being configured, it will be automatically assigned by the configuration mechanism. The identifiers are assigned from 1 and are monotonically increased for each subsequent subnet: 1, 2, 3 .... If there are multiple subnets configured with auto-generated identifiers and one of them is removed, the subnet identifiers may be renumbered. For example: if there are four subnets and the third is removed the last subnet will be assigned the identifier that the third subnet had before removal. As a result, the leases stored in the lease database for subnet 3 are now associated with subnet 4, something that may have unexpected consequences. It is planned to implement a mechanism to preserve auto-generated subnet ids in a future version of Kea. However, the only remedy for this issue at present is to manually specify a unique identifier for each subnet. The following configuration will assign the specified subnet identifier to the newly configured subnet: "Dhcp4": { "subnet4": [ { "subnet": "192.0.2.0/24", "id": 1024, ... } ] } This identifier will not change for this subnet unless the "id" parameter is removed or set to 0. The value of 0 forces auto-generation of the subnet identifier.
Configuration of IPv4 Address Pools The main role of a DHCPv4 server is address assignment. For this, the server has to be configured with at least one subnet and one pool of dynamic addresses for it to manage. For example, assume that the server is connected to a network segment that uses the 192.0.2.0/24 prefix. The Administrator of that network has decided that addresses from range 192.0.2.10 to 192.0.2.20 are going to be managed by the Dhcp4 server. Such a configuration can be achieved in the following way: "Dhcp4": { "subnet4": [ { "subnet": "192.0.2.0/24", "pools": [ { "pool": "192.0.2.10 - 192.0.2.20" } ], ... } ] } Note that subnet is defined as a simple string, but the pools parameter is actually a list of pools: for this reason, the pool definition is enclosed in square brackets, even though only one range of addresses is specified. Each pool is a structure that contains the parameters that describe a single pool. Currently there is only one parameter, pool, which gives the range of addresses in the pool. Additional parameters will be added in future releases of Kea. It is possible to define more than one pool in a subnet: continuing the previous example, further assume that 192.0.2.64/26 should be also be managed by the server. It could be written as 192.0.2.64 to 192.0.2.127. Alternatively, it can be expressed more simply as 192.0.2.64/26. Both formats are supported by Dhcp4 and can be mixed in the pool list. For example, one could define the following pools: "Dhcp4": { "subnet4": [ { "subnet": "192.0.2.0/24", "pools": [ { "pool": "192.0.2.10-192.0.2.20" }, { "pool": "192.0.2.64/26" } ], ... } ], ... } White space in pool definitions is ignored, so spaces before and after the hyphen are optional. They can be used to improve readability. The number of pools is not limited, but for performance reasons it is recommended to use as few as possible. The server may be configured to serve more than one subnet: "Dhcp4": { "subnet4": [ { "subnet": "192.0.2.0/24", "pools": [ { "pool": "192.0.2.1 - 192.0.2.200" } ], ... }, { "subnet": "192.0.3.0/24", "pools": [ { "pool": "192.0.3.100 - 192.0.3.200" } ], ... }, { "subnet": "192.0.4.0/24", "pools": [ { "pool": "192.0.4.1 - 192.0.4.254" } ], ... } ] } When configuring a DHCPv4 server using prefix/length notation, please pay attention to the boundary values. When specifying that the server can use a given pool, it will also be able to allocate the first (typically network address) and the last (typically broadcast address) address from that pool. In the aforementioned example of pool 192.0.3.0/24, both 192.0.3.0 and 192.0.3.255 addresses may be assigned as well. This may be invalid in some network configurations. If you want to avoid this, please use the "min-max" notation.
Standard DHCPv4 Options One of the major features of the DHCPv4 server is to provide configuration options to clients. Most of the options are sent by the server only if the client explicitly requests them using the Parameter Request List option. Those that do not require inclusion in the Parameter Request List option are commonly used options, e.g. "Domain Server", and options which require special behavior, e.g. "Client FQDN" is returned to the client if the client has included this option in its message to the server. comprises the list of the standard DHCPv4 options whose values can be configured using the configuration structures described in this section. This table excludes the options which require special processing and thus cannot be configured with some fixed values. The last column of the table indicates which options can be sent by the server even when they are not requested in the Parameter Request list option, and those which are sent only when explicitly requested. The following example shows how to configure the addresses of DNS servers, which is one of the most frequently used options. Options specified in this way are considered global and apply to all configured subnets. "Dhcp4": { "option-data": [ { "name": "domain-name-servers", "code": 6, "space": "dhcp4", "csv-format": true, "data": "192.0.2.1, 192.0.2.2" }, ... ] } The name parameter specifies the option name. For a list of currently supported names, see below. The code parameter specifies the option code, which must match one of the values from that list. The next line specifies the option space, which must always be set to "dhcp4" as these are standard DHCPv4 options. For other option spaces, including custom option spaces, see . The next line specifies the format in which the data will be entered: use of CSV (comma separated values) is recommended. The sixth line gives the actual value to be sent to clients. Data is specified as normal text, with values separated by commas if more than one value is allowed. Options can also be configured as hexadecimal values. If csv-format is set to false, option data must be specified as a hexadecimal string. The following commands configure the domain-name-servers option for all subnets with the following addresses: 192.0.3.1 and 192.0.3.2. Note that csv-format is set to false. "Dhcp4": { "option-data": [ { "name": "domain-name-servers", "code": 6, "space": "dhcp4", "csv-format": false, "data": "C0 00 03 01 C0 00 03 02" }, ... ], ... } Most of the parameters in the "option-data" structure are optional and can be omitted in some circumstances as discussed in the . It is possible to specify or override options on a per-subnet basis. If clients connected to most of your subnets are expected to get the same values of a given option, you should use global options: you can then override specific values for a small number of subnets. On the other hand, if you use different values in each subnet, it does not make sense to specify global option values (Dhcp4/option-data), rather you should set only subnet-specific values (Dhcp4/subnet[X]/option-data[Y]). The following commands override the global DNS servers option for a particular subnet, setting a single DNS server with address 192.0.2.3. "Dhcp4": { "subnet4": [ { "option-data": [ { "name": "domain-name-servers", "code": 6, "space": "dhcp4", "csv-format": true, "data": "192.0.2.3" }, ... ], ... }, ... ], ... } The currently supported standard DHCPv4 options are listed in and . The "Name" and "Code" are the values that should be used as a name in the option-data structures. "Type" designates the format of the data: the meanings of the various types is given in . Some options are designated as arrays, which means that more than one value is allowed in such an option. For example the option time-servers allows the specification of more than one IPv4 address, so allowing clients to obtain the addresses of multiple NTP servers. The describes the configuration syntax to create custom option definitions (formats). It is generally not allowed to create custom definitions for standard options, even if the definition being created matches the actual option format defined in the RFCs. There is an exception from this rule for standard options for which Kea currently does not provide a definition. In order to use such options, a server administrator must create a definition as described in in the 'dhcp4' option space. This definition should match the option format described in the relevant RFC but the configuration mechanism will allow any option format as it presently has no means to validate it. List of standard DHCPv4 options Name Code Type Array? Returned if not requested? time-offset2int32falsefalserouters3ipv4-addresstruetruetime-servers4ipv4-addresstruefalsename-servers5ipv4-addresstruefalsedomain-name-servers6ipv4-addresstruetruelog-servers7ipv4-addresstruefalsecookie-servers8ipv4-addresstruefalselpr-servers9ipv4-addresstruefalseimpress-servers10ipv4-addresstruefalseresource-location-servers11ipv4-addresstruefalseboot-size13uint16falsefalsemerit-dump14stringfalsefalsedomain-name15fqdnfalsetrueswap-server16ipv4-addressfalsefalseroot-path17stringfalsefalseextensions-path18stringfalsefalseip-forwarding19booleanfalsefalsenon-local-source-routing20booleanfalsefalsepolicy-filter21ipv4-addresstruefalsemax-dgram-reassembly22uint16falsefalsedefault-ip-ttl23uint8falsefalsepath-mtu-aging-timeout24uint32falsefalsepath-mtu-plateau-table25uint16truefalseinterface-mtu26uint16falsefalseall-subnets-local27booleanfalsefalsebroadcast-address28ipv4-addressfalsefalseperform-mask-discovery29booleanfalsefalsemask-supplier30booleanfalsefalserouter-discovery31booleanfalsefalserouter-solicitation-address32ipv4-addressfalsefalsestatic-routes33ipv4-addresstruefalsetrailer-encapsulation34booleanfalsefalsearp-cache-timeout35uint32falsefalseieee802-3-encapsulation36booleanfalsefalsedefault-tcp-ttl37uint8falsefalsetcp-keepalive-interval38uint32falsefalsetcp-keepalive-garbage39booleanfalsefalse
List of standard DHCPv4 options (continued) Name Code Type Array? Returned if not requested? nis-domain40stringfalsefalsenis-servers41ipv4-addresstruefalsentp-servers42ipv4-addresstruefalsevendor-encapsulated-options43emptyfalsefalsenetbios-name-servers44ipv4-addresstruefalsenetbios-dd-server45ipv4-addresstruefalsenetbios-node-type46uint8falsefalsenetbios-scope47stringfalsefalsefont-servers48ipv4-addresstruefalsex-display-manager49ipv4-addresstruefalsedhcp-option-overload52uint8falsefalsedhcp-message56stringfalsefalsedhcp-max-message-size57uint16falsefalsevendor-class-identifier60binaryfalsefalsenwip-domain-name62stringfalsefalsenwip-suboptions63binaryfalsefalsenisplus-domain-name64stringfalsefalsenisplus-servers65ipv4-addresstruefalsetftp-server-name66stringfalsefalseboot-file-name67stringfalsefalsemobile-ip-home-agent68ipv4-addresstruefalsesmtp-server69ipv4-addresstruefalsepop-server70ipv4-addresstruefalsenntp-server71ipv4-addresstruefalsewww-server72ipv4-addresstruefalsefinger-server73ipv4-addresstruefalseirc-server74ipv4-addresstruefalsestreettalk-server75ipv4-addresstruefalsestreettalk-directory-assistance-server76ipv4-addresstruefalseuser-class77binaryfalsefalseclient-system93uint16truefalseclient-ndi94record (uint8, uint8, uint8)falsefalseuuid-guid97record (uint8, binary)falsefalsesubnet-selection118ipv4-addressfalsefalsedomain-search119binaryfalsefalsevivco-suboptions124binaryfalsefalsevivso-suboptions125binaryfalsefalse
List of standard DHCP option types NameMeaningbinaryAn arbitrary string of bytes, specified as a set of hexadecimal digits.booleanBoolean value with allowed values true or falseemptyNo value, data is carried in suboptionsfqdnFully qualified domain name (e.g. www.example.com)ipv4-addressIPv4 address in the usual dotted-decimal notation (e.g. 192.0.2.1)ipv6-addressIPv6 address in the usual colon notation (e.g. 2001:db8::1)recordStructured data that may comprise any types (except "record" and "empty")stringAny textuint88 bit unsigned integer with allowed values 0 to 255uint1616 bit unsigned integer with allowed values 0 to 65535uint3232 bit unsigned integer with allowed values 0 to 4294967295
Custom DHCPv4 options Kea supports custom (non-standard) DHCPv4 options. Assume that we want to define a new DHCPv4 option called "foo" which will have a code 222 and will convey a single unsigned 32 bit integer value. We can define such an option by using the following entry in the configuration file: "Dhcp4": { "option-def": [ { "name": "foo", "code": 222, "type": "uint32", "array": false, "record-types": "", "space": "dhcp4", "encapsulate": "" }, ... ], ... } The false value of the array parameter determines that the option does NOT comprise an array of "uint32" values but is, instead, a single value. Two other parameters have been left blank: record-types and encapsulate. The former specifies the comma separated list of option data fields if the option comprises a record of data fields. This should be non-empty if the type is set to "record". Otherwise it must be left blank. The latter parameter specifies the name of the option space being encapsulated by the particular option. If the particular option does not encapsulate any option space it should be left blank. Note that the above set of comments define the format of the new option and do not set its values. The name, code and type parameters are required, all others are optional. The array default value is false. The record-types and encapsulate default values are blank (i.e. ""). The default space is "dhcp4". Once the new option format is defined, its value is set in the same way as for a standard option. For example the following commands set a global value that applies to all subnets. "Dhcp4": { "option-data": [ { "name": "foo", "code": 222, "space": "dhcp4", "csv-format": true, "data": "12345" }, ... ], ... } New options can take more complex forms than simple use of primitives (uint8, string, ipv4-address etc): it is possible to define an option comprising a number of existing primitives. Assume we want to define a new option that will consist of an IPv4 address, followed by an unsigned 16 bit integer, followed by a boolean value, followed by a text string. Such an option could be defined in the following way: "Dhcp4": { "option-def": [ { "name": "bar", "code": 223, "space": "dhcp4", "type": "record", "array": false, "record-types": "ipv4-address, uint16, boolean, string", "encapsulate": "" }, ... ], ... } The type is set to "record" to indicate that the option contains multiple values of different types. These types are given as a comma-separated list in the record-types field and should be ones from those listed in . The values of the option are set as follows: "Dhcp4": { "option-data": [ { "name": "bar", "space": "dhcp4", "code": 223, "csv-format": true, "data": "192.0.2.100, 123, true, Hello World" } ], ... } csv-format is set to true to indicate that the data field comprises a command-separated list of values. The values in the data must correspond to the types set in the record-types field of the option definition. In the general case, boolean values are specified as true or false, without quotes. Some specific boolean parameters may accept also "true", "false", 0, 1, "0" and "1". Future versions of Kea will accept all those values for all boolean parameters.
DHCPv4 Vendor Specific Options Currently there are two option spaces defined for the DHCPv4 daemon: "dhcp4" (for the top level DHCPv4 options) and "vendor-encapsulated-options-space", which is empty by default but in which options can be defined. Such options will be carried in the Vendor Specific Information option (code 43). The following examples show how to define an option "foo" in that space that has a code 1, and comprises an IPv4 address, an unsigned 16 bit integer and a string. The "foo" option is conveyed in a Vendor Specific Information option. The first step is to define the format of the option: "Dhcp4": { "option-def": [ { "name": "foo", "code": 1, "space": "vendor-encapsulated-options-space", "type": "record", "array": false, "record-types": "ipv4-address, uint16, string", "encapsulate": "" } ], ... } (Note that the option space is set to "vendor-encapsulated-options-space".) Once the option format is defined, the next step is to define actual values for that option: "Dhcp4": { "option-data": [ { "name": "foo", "space": "vendor-encapsulated-options-space", "code": 1, "csv-format": true, "data": "192.0.2.3, 123, Hello World" } ], ... } We also include the Vendor Specific Information option, the option that conveys our sub-option "foo". This is required, else the option will not be included in messages sent to the client. "Dhcp4": { "option-data": [ { "name": "vendor-encapsulated-options" } ], ... } Alternatively, the option can be specified using its code. "Dhcp4": { "option-data": [ { "code": 43 } ], ... }
Nested DHCPv4 Options (Custom Option Spaces) It is sometimes useful to define a completely new option space. This is the case when user creates new option in the standard option space ("dhcp4") and wants this option to convey sub-options. Since they are in a separate space, sub-option codes will have a separate numbering scheme and may overlap with the codes of standard options. Note that creation of a new option space when defining sub-options for a standard option is not required, because it is created by default if the standard option is meant to convey any sub-options (see ). Assume that we want to have a DHCPv4 option called "container" with code 222 that conveys two sub-options with codes 1 and 2. First we need to define the new sub-options: "Dhcp4": { "option-def": [ { "name": "subopt1", "code": 1, "space": "isc", "type": "ipv4-address", "record-types": "", "array": false, "encapsulate": "" }, { "name": "subopt2", "code": 2, "space": "isc", "type": "string", "record-types": "", "array": false, "encapsulate": "" } ], ... } Note that we have defined the options to belong to a new option space (in this case, "isc"). The next step is to define a regular DHCPv4 option with our desired code and specify that it should include options from the new option space: "Dhcp4": { "option-def": [ ..., { "name": "container", "code": 222, "space": "dhcp4", "type": "empty", "array": false, "record-types": "", "encapsulate": "isc" } ], ... } The name of the option space in which the sub-options are defined is set in the encapsulate field. The type field is set to "empty" to indicate that this option does not carry any data other than sub-options. Finally, we can set values for the new options: "Dhcp4": { "option-data": [ { "name": "subopt1", "code": 1, "space": "isc", "data": "192.0.2.3" }, } "name": "subopt2", "code": 2, "space": "isc", "data": "Hello world" }, { "name": "container", "code": 222, "space": "dhcp4" } ], ... } Note that it is possible to create an option which carries some data in addition to the sub-options defined in the encapsulated option space. For example, if the "container" option from the previous example was required to carry an uint16 value as well as the sub-options, the type value would have to be set to "uint16" in the option definition. (Such an option would then have the following data structure: DHCP header, uint16 value, sub-options.) The value specified with the data parameter — which should be a valid integer enclosed in quotes, e.g. "123" — would then be assigned to the uint16 field in the "container" option.
Unspecified Parameters for DHCPv4 Option Configuration In many cases it is not required to specify all parameters for an option configuration and the default values may be used. However, it is important to understand the implications of not specifying some of them as it may result in configuration errors. The list below explains the behavior of the server when a particular parameter is not explicitly specified: name - the server requires an option name or option code to identify an option. If this parameter is unspecified, the option code must be specified. code - the server requires an option name or option code to identify an option. This parameter may be left unspecified if the name parameter is specified. However, this also requires that the particular option has its definition (it is either a standard option or an administrator created a definition for the option using an 'option-def' structure), as the option definition associates an option with a particular name. It is possible to configure an option for which there is no definition (unspecified option format). Configuration of such options requires the use of option code. space - if the option space is unspecified it will default to 'dhcp4' which is an option space holding DHCPv4 standard options. data - if the option data is unspecified it defaults to an empty value. The empty value is mostly used for the options which have no payload (boolean options), but it is legal to specify empty values for some options which carry variable length data and which the specification allows for the length of 0. For such options, the data parameter may be omitted in the configuration. csv-format - if this value is not specified and the definition for the particular option exists, the server will assume that the option data is specified as a list of comma separated values to be assigned to individual fields of the DHCP option. If the definition does not exist for this option, the server will assume that the data parameter contains the option payload in the binary format (represented as a string of hexadecimal digits). Note that not specifying this parameter doesn't imply that it defaults to a fixed value, but the configuration data interpretation also depends on the presence of the option definition. An administrator must be aware if the definition for the particular option exists when this parameter is not specified. It is generally recommended to not specify this parameter only for the options for which the definition exists, e.g. standard options. Setting csv-format to an explicit value will cause the server to strictly check the format of the option data specified.
Stateless Configuration of DHCPv4 Clients The DHCPv4 server supports the stateless client configuration whereby the client has an IP address configured (e.g. using manual configuration) and only contacts the server to obtain other configuration parameters, e.g. addresses of DNS servers. In order to obtain the stateless configuration parameters the client sends the DHCPINFORM message to the server with the "ciaddr" set to the address that the client is currently using. The server unicasts the DHCPACK message to the client that includes the stateless configuration ("yiaddr" not set). The server will respond to the DHCPINFORM when the client is associated with a subnet defined in the server's configuration. An example subnet configuration will look like this: "Dhcp4": { "subnet4": [ { "subnet": "192.0.2.0/24" "option-data": [ { "name": "domain-name-servers", "code": 6, "data": "192.0.2.200,192.0.2.201", "csv-format": true, "space": "dhcp4" } ] } ] } This subnet specifies the single option which will be included in the DHCPACK message to the client in response to DHCPINFORM. Note that the subnet definition does not require the address pool configuration if it will be used solely for the stateless configuration. This server will associate the subnet with the client if one of the following conditions is met: The DHCPINFORM is relayed and the giaddr matches the configured subnet. The DHCPINFORM is unicast from the client and the ciaddr matches the configured subnet. The DHCPINFORM is unicast from the client, the ciaddr is not set but the source address of the IP packet matches the configured subnet. The DHCPINFORM is not relayed and the IP address on the interface on which the message is received matches the configured subnet.
Client Classification in DHCPv4 The DHCPv4 server includes support for client classification. For a deeper discussion of the classification process see . In certain cases it is useful to differentiate between different types of clients and treat them accordingly. It is envisaged that client classification will be used for changing the behavior of almost any part of the DHCP message processing, including the assignment of leases from different pools, the assignment of different options (or different values of the same options) etc. In the current release of the software however, there are only three mechanisms that take advantage of client classification: subnet selection, assignment of different options, and, for cable modems, there are specific options for use with the TFTP server address and the boot file field. Kea can be instructed to limit access to given subnets based on class information. This is particularly useful for cases where two types of devices share the same link and are expected to be served from two different subnets. The primary use case for such a scenario is cable networks. Here, there are two classes of devices: the cable modem itself, which should be handed a lease from subnet A and all other devices behind the modem that should get a lease from subnet B. That segregation is essential to prevent overly curious users from playing with their cable modems. For details on how to set up class restrictions on subnets, see . The process of doing classification is conducted in three steps. The first step is to assess an incoming packet and assign it to zero or more classes. The second step is to choose a subnet, possibly based on the class information. The third step is to assign options, again possibly based on the class information. There are two methods of doing classification. The first is automatic and relies on examining the values in the vendor class options. Information from these options is extracted and a class name is constructed from it and added to the class list for the packet. The second allows you to specify an expression that is evaluated for each packet. If the result is true the packet is a member of the class. Care should be taken with client classification as it is easy for clients that do not meet class criteria to be denied any service altogether.
Setting Fixed Fields in Classification It is possible to specify that clients belonging to a particular class should receive packets with specific values in certain fixed fields. In particular, three fixed fields are supported: next-server (that conveys an IPv4 address, which is set in the siaddr field), server-hostname (that conveys a server hostname, can be up to 64 bytes long and will be sent in the sname field) and boot-file-name (that conveys the configuration file, can be up to 128 bytes long and will be sent using file field). Obviously, there are many ways to assign clients to specific classes, but for the PXE clients the client architecture type option (code 93) seems to be particularly suited to make the distinction. The following example checks if the client identifies itself as PXE device with architecture EFI x86-64, and sets several fields if it does. See Section 2.1 of RFC 4578) or the documentation of your client for specific values. "Dhcp4": { "client-classes": [ { "name": "ipxe_efi_x64", "test": "option[93].hex == 0x0009", "next-server": "192.0.2.254", "server-hostname": "hal9000", "boot-file-name": "/dev/null" }, ... ], ... } If there are multiple classes defined and an incoming packet is matched to multiple classes, the class whose name is alphabetically the first is used.
Using Vendor Class Information in Classification The server checks whether an incoming packet includes the vendor class identifier option (60). If it does, the content of that option is prepended with "VENDOR_CLASS_", it is interpreted as a class. For example, modern cable modems will send this option with value "docsis3.0" and as a result the packet will belong to class "VENDOR_CLASS_docsis3.0". Kea 1.0 and earlier versions performed special actions for clients that were in VENDOR_CLASS_docsis3.0. This is no longer the case in Kea 1.1 and later. In these versions the old behavior can be achieved by defining VENDOR_CLASS_docsis3.0 and setting its next-server and boot-file-name values appropriately. This example shows a configuration using an automatically generated "VENDOR_CLASS_" class. The administrator of the network has decided that addresses from range 192.0.2.10 to 192.0.2.20 are going to be managed by the Dhcp4 server and only clients belonging to the docsis3.0 client class are allowed to use that pool. "Dhcp4": { "subnet4": [ { "subnet": "192.0.2.0/24", "pools": [ { "pool": "192.0.2.10 - 192.0.2.20" } ], "client-class": "VENDOR_CLASS_docsis3.0" } ], ... }
Defining and Using Custom Classes The following example shows how to configure a class using an expression and a subnet that makes use of the class. This configuration defines the class named "Client_foo". It is comprised of all clients who's client ids (option 61) start with the string "foo". Members of this class will be given addresses from 192.0.2.10 to 192.0.2.20 and the addresses of their DNS servers set to 192.0.2.1 and 192.0.2.2. "Dhcp4": { "client-classes": [ { "name": "Client_foo", "test": "substring(option[61].hex,0,3) == 'foo'", "option-data": [ { "name": "domain-name-servers", "code": 6, "space": "dhcp4", "csv-format": true, "data": "192.0.2.1, 192.0.2.2" } ] }, ... ], "subnet4": [ { "subnet": "192.0.2.0/24", "pools": [ { "pool": "192.0.2.10 - 192.0.2.20" } ], "client-class": "Client_foo" }, ... ], ... }
DDNS for DHCPv4 As mentioned earlier, kea-dhcp4 can be configured to generate requests to the DHCP-DDNS server (referred to here as "D2" ) to update DNS entries. These requests are known as NameChangeRequests or NCRs. Each NCR contains the following information: Whether it is a request to add (update) or remove DNS entries Whether the change requests forward DNS updates (A records), reverse DNS updates (PTR records), or both. The FQDN, lease address, and DHCID The parameters for controlling the generation of NCRs for submission to D2 are contained in the dhcp-ddns section of the kea-dhcp4 server configuration. The mandatory parameters for the DHCP DDNS configuration are enable-updates which is unconditionally required, and qualifying-suffix which has no default value and is required when enable-updates is set to true. The two (disabled and enabled) minimal DHCP DDNS configurations are: "Dhcp4": { "dhcp-ddns": { "enable-updates": false }, ... } and for example: "Dhcp4": { "dhcp-ddns": { "enable-updates": true, "qualifying-suffix": "example." }, ... } The default values for the "dhcp-ddns" section are as follows: "server-ip": "127.0.0.1" "server-port": 53001 "sender-ip": "" "sender-port": 0 "max-queue-size": 1024 "ncr-protocol": "UDP" "ncr-format": "JSON" "override-no-update": false "override-client-update": false "replace-client-name": "never" "generated-prefix": "myhost"
DHCP-DDNS Server Connectivity In order for NCRs to reach the D2 server, kea-dhcp4 must be able to communicate with it. kea-dhcp4 uses the following configuration parameters to control this communication: enable-updates - determines whether or not kea-dhcp4 will generate NCRs. By default, this value is false hence DDNS updates are disabled. To enable DDNS updates set this value to true: server-ip - IP address on which D2 listens for requests. The default is the local loopback interface at address 127.0.0.1. You may specify either an IPv4 or IPv6 address. server-port - port on which D2 listens for requests. The default value is 53001. sender-ip - IP address which kea-dhcp4 should use to send requests to D2. The default value is blank which instructs kea-dhcp4 to select a suitable address. sender-port - port which kea-dhcp4 should use to send requests to D2. The default value of 0 instructs kea-dhcp4 to select a suitable port. max-queue-size - maximum number of requests allowed to queue waiting to be sent to D2. This value guards against requests accumulating uncontrollably if they are being generated faster than they can be delivered. If the number of requests queued for transmission reaches this value, DDNS updating will be turned off until the queue backlog has been sufficiently reduced. The intention is to allow the kea-dhcp4 server to continue lease operations without running the risk that its memory usage grows without limit. The default value is 1024. ncr-protocol - socket protocol use when sending requests to D2. Currently only UDP is supported. TCP may be available in an upcoming release. ncr-format - packet format to use when sending requests to D2. Currently only JSON format is supported. Other formats may be available in future releases. By default, kea-dhcp-ddns is assumed to be running on the same machine as kea-dhcp4, and all of the default values mentioned above should be sufficient. If, however, D2 has been configured to listen on a different address or port, these values must be altered accordingly. For example, if D2 has been configured to listen on 192.168.1.10 port 900, the following configuration would be required: "Dhcp4": { "dhcp-ddns": { "server-ip": "192.168.1.10", "server-port": 900, ... }, ... }
When Does the kea-dhcp4 Server Generate DDNS Requests? kea-dhcp4 follows the behavior prescribed for DHCP servers in RFC 4702. It is important to keep in mind that kea-dhcp4 provides the initial decision making of when and what to update and forwards that information to D2 in the form of NCRs. Carrying out the actual DNS updates and dealing with such things as conflict resolution are within the purview of D2 itself (). This section describes when kea-dhcp4 will generate NCRs and the configuration parameters that can be used to influence this decision. It assumes that the enable-updates parameter is true. In general, kea-dhcp4 will generate DDNS update requests when: A new lease is granted in response to a DHCP REQUEST An existing lease is renewed but the FQDN associated with it has changed. An existing lease is released in response to a DHCP RELEASE In the second case, lease renewal, two DDNS requests will be issued: one request to remove entries for the previous FQDN and a second request to add entries for the new FQDN. In the last case, a lease release, a single DDNS request to remove its entries will be made. The decision making involved when granting a new lease (the first case) is more involved. When a new lease is granted, kea-dhcp4 will generate a DDNS update request if the DHCP REQUEST contains either the FQDN option (code 81) or the Host Name option (code 12). If both are present, the server will use the FQDN option. By default kea-dhcp4 will respect the FQDN N and S flags specified by the client as shown in the following table: Default FQDN Flag Behavior Client Flags:N-S Client Intent Server Response Server Flags:N-S-O 0-0 Client wants to do forward updates, server should do reverse updates Server generates reverse-only request 1-0-0 0-1 Server should do both forward and reverse updates Server generates request to update both directions 0-1-0 1-0 Client wants no updates done Server does not generate a request 1-0-0
The first row in the table above represents "client delegation". Here the DHCP client states that it intends to do the forward DNS updates and the server should do the reverse updates. By default, kea-dhcp4 will honor the client's wishes and generate a DDNS request to the D2 server to update only reverse DNS data. The parameter override-client-update can be used to instruct the server to override client delegation requests. When this parameter is true, kea-dhcp4 will disregard requests for client delegation and generate a DDNS request to update both forward and reverse DNS data. In this case, the N-S-O flags in the server's response to the client will be 0-1-1 respectively. (Note that the flag combination N=1, S=1 is prohibited according to RFC 4702. If such a combination is received from the client, the packet will be dropped by kea-dhcp4.) To override client delegation, set the following values in the configuration file: "Dhcp4": { "dhcp-ddns": { "override-client-update": true, ... }, ... } The third row in the table above describes the case in which the client requests that no DNS updates be done. The parameter, override-no-update, can be used to instruct the server to disregard the client's wishes. When this parameter is true, kea-dhcp4 will generate DDNS update requests to kea-dhcp-ddns even if the client requests that no updates be done. The N-S-O flags in the server's response to the client will be 0-1-1. To override client delegation, the following values should be set in your configuration: "Dhcp4": { "dhcp-ddns": { "override-no-update": true, ... }, ... } kea-dhcp4 will always generate DDNS update requests if the client request only contains the Host Name option. In addition it will include an FQDN option in the response to the client with the FQDN N-S-O flags set to 0-1-0 respectively. The domain name portion of the FQDN option will be the name submitted to D2 in the DDNS update request.
kea-dhcp4 name generation for DDNS update requests Each NameChangeRequest must of course include the fully qualified domain name whose DNS entries are to be affected. kea-dhcp4 can be configured to supply a portion or all of that name based upon what it receives from the client in the DHCP REQUEST. The default rules for constructing the FQDN that will be used for DNS entries are: If the DHCPREQUEST contains the client FQDN option, the candidate name is taken from there, otherwise it is taken from the Host Name option. If the candidate name is a partial (i.e. unqualified) name then add a configurable suffix to the name and use the result as the FQDN. If the candidate name provided is empty, generate a FQDN using a configurable prefix and suffix. If the client provided neither option, then no DNS action will be taken. These rules can amended by setting the replace-client-name parameter which provides the following modes of behavior: never - Use the name the client sent. If the client sent no name, do not generate one. This is the default mode. always - Replace the name the client sent. If the client sent no name, generate one for the client. when-present - Replace the name the client sent. If the client sent no name, do not generate one. when-not-present - Use the name the client sent. If the client sent no name, generate one for the client. Note that formerly, this parameter was a boolean and permitted only values of true and false. Boolean values will still be accepted but may eventually be deprecated. A value of true equates to when-present, false equates to never. For example, To instruct kea-dhcp4 to always generate the FQDN for a client, set the parameter replace-client-name to always as follows: "Dhcp4": { "dhcp-ddns": { "replace-client-name": "always", ... }, ... } The prefix used in the generation of a FQDN is specified by the generated-prefix parameter. The default value is "myhost". To alter its value, simply set it to the desired string: "Dhcp4": { "dhcp-ddns": { "generated-prefix": "another.host", ... }, ... } The suffix used when generating a FQDN or when qualifying a partial name is specified by the qualifying-suffix parameter. This parameter has no default value, thus it is mandatory when DDNS updates are enabled. To set its value simply set it to the desired string: "Dhcp4": { "dhcp-ddns": { "qualifying-suffix": "foo.example.org", ... }, ... }
When generating a name, kea-dhcp4 will construct name of the format: [generated-prefix]-[address-text].[qualifying-suffix]. where address-text is simply the lease IP address converted to a hyphenated string. For example, if the lease address is 172.16.1.10, the qualifying suffix "example.com", and the default value is used for generated-prefix, the generated FQDN would be: myhost-172-16-1-10.example.com.
Next Server (siaddr) In some cases, clients want to obtain configuration from a TFTP server. Although there is a dedicated option for it, some devices may use the siaddr field in the DHCPv4 packet for that purpose. That specific field can be configured using next-server directive. It is possible to define it in the global scope or for a given subnet only. If both are defined, the subnet value takes precedence. The value in subnet can be set to 0.0.0.0, which means that next-server should not be sent. It may also be set to an empty string, which means the same as if it was not defined at all, i.e. use the global value. "Dhcp4": { "next-server": "192.0.2.123", ..., "subnet4": [ { "next-server": "192.0.2.234", ... } ] }
Echoing Client-ID (RFC 6842) The original DHCPv4 specification (RFC 2131) states that the DHCPv4 server must not send back client-id options when responding to clients. However, in some cases that confused clients that did not have MAC address or client-id; see RFC 6842. for details. That behavior has changed with the publication of RFC 6842 which updated RFC 2131. That update states that the server must send client-id if the client sent it. That is Kea's default behavior. However, in some cases older devices that do not support RFC 6842. may refuse to accept responses that include the client-id option. To enable backward compatibility, an optional configuration parameter has been introduced. To configure it, use the following configuration statement: "Dhcp4": { "echo-client-id": false, ... }
Using Client Identifier and Hardware Address The DHCP server must be able to identify the client (and distinguish it from other clients) from which it receives the message. There are many reasons why this identification is required and the most important ones are: When the client contacts the server to allocate a new lease, the server must store the client identification information in the lease database as a search key. When the client is trying to renew or release the existing lease, the server must be able to find the existing lease entry in the database for this client, using the client identification information as a search key. Some configurations use static reservations for the IP addresses and other configuration information. The server's administrator uses client identification information to create these static assignments. In the dual stack networks there is often a need to correlate the lease information stored in DHCPv4 and DHCPv6 server for a particular host. Using common identification information by the DHCPv4 and DHCPv6 client allows the network administrator to achieve this correlation and better administer the network. DHCPv4 makes use of two distinct identifiers which are placed by the client in the queries sent to the server and copied by the server to its responses to the client: "chaddr" and "client identifier". The former was introduced as a part of the BOOTP specification and it is also used by DHCP to carry the hardware address of the interface used to send the query to the server (MAC address for the Ethernet). The latter is carried in the Client-identifier option, introduced in RFC 2132. RFC 2131 indicates that the server may use both of these identifiers to identify the client but the "client identifier", if present, takes precedence over "chaddr". One of the reasons for this is that "client identifier" is independent from the hardware used by the client to communicate with the server. For example, if the client obtained the lease using one network card and then the network card is moved to another host, the server will wrongly identify this host is the one which has obtained the lease. Moreover, RFC 4361 gives the recommendation to use a DUID (see RFC 3315, the DHCPv6 specification) carried as "client identifier" when dual stack networks are in use to provide consistent identification information of the client, regardless of the protocol type it is using. Kea adheres to these specifications and the "client identifier" by default takes precedence over the value carried in "chaddr" field when the server searches, creates, updates or removes the client's lease. When the server receives a DHCPDISCOVER or DHCPREQUEST message from the client, it will try to find out if the client already has a lease in the database and will hand out that lease rather than allocate a new one. Each lease in the lease database is associated with the "client identifier" and/or "chaddr". The server will first use the "client identifier" (if present) to search the lease. If the lease is found, the server will treat this lease as belonging to the client even if the current "chaddr" and the "chaddr" associated with the lease do not match. This facilitates the scenario when the network card on the client system has been replaced and thus the new MAC address appears in the messages sent by the DHCP client. If the server fails to find the lease using the "client identifier" it will perform another lookup using the "chaddr". If this lookup returns no result, the client is considered as not having a lease and the new lease will be created. A common problem reported by network operators is that poor client implementations do not use stable client identifiers, instead generating a new "client identifier" each time the client connects to the network. Another well known case is when the client changes its "client identifier" during the multi-stage boot process (PXE). In such cases, the MAC address of the client's interface remains stable and using "chaddr" field to identify the client guarantees that the particular system is considered to be the same client, even though its "client identifier" changes. To address this problem, Kea includes a configuration option which enables client identification using "chaddr" only by instructing the server to disregard server to "ignore" the "client identifier" during lease lookups and allocations for a particular subnet. Consider the following simplified server configuration: "Dhcp4": { ... "match-client-id": true, ... "subnet4": [ { "subnet": "192.0.10.0/24", "pools": [ { "pool": "192.0.2.23-192.0.2.87" } ], "match-client-id": false }, { "subnet": "10.0.0.0/8", "pools": [ { "pool": "10.0.0.23-10.0.2.99" } ], } ] } The match-client-id is a boolean value which controls this behavior. The default value of true indicates that the server will use the "client identifier" for lease lookups and "chaddr" if the first lookup returns no results. The false means that the server will only use the "chaddr" to search for client"s lease. Whether the DHCID for DNS updates is generated from the "client identifier" or "chaddr" is controlled through the same parameter accordingly. The match-client-id parameter may appear both in the global configuration scope and/or under any subnet declaration. In the example shown above, the effective value of the match-client-id will be false for the subnet 192.0.10.0/24, because the subnet specific setting of the parameter overrides the global value of the parameter. The effective value of the match-client-id for the subnet 10.0.0.0/8 will be set to true because the subnet declaration lacks this parameter and the global setting is by default used for this subnet. In fact, the global entry for this parameter could be omitted in this case, because true is the default value. It is important to explain what happens when the client obtains its lease for one setting of the match-client-id and then renews when the setting has been changed. First consider the case when the client obtains the lease when the match-client-id is set to true. The server will store the lease information including "client identifier" (if supplied) and "chaddr" in the lease database. When the setting is changed and the client renews the lease the server will determine that it should use the "chaddr" to search for the existing lease. If the client hasn't changed its MAC address the server should successfully find the existing lease. The "client identifier" associated with the returned lease is ignored and the client is allowed to use this lease. When the lease is renewed only the "chaddr" is recorded for this lease according to the new server setting. In the second case the client has the lease with only a "chaddr" value recorded. When the setting is changed to match-client-id set to true the server will first try to use the "client identifier" to find the existing client's lease. This will return no results because the "client identifier" was not recorded for this lease. The server will then use the "chaddr" and the lease will be found. If the lease appears to have no "client identifier" recorded, the server will assume that this lease belongs to the client and that it was created with the previous setting of the match-client-id. However, if the lease contains "client identifier" which is different from the "client identifier" used by the client the lease will be assumed to belong to another client and the new lease will be allocated.
DHCPv4-over-DHCPv6: DHCPv4 Side The support of DHCPv4-over-DHCPv6 transport is described in RFC 7341 and is implemented using cooperating DHCPv4 and DHCPv6 servers. This section is about the configuration of the DHCPv4 side (the DHCPv6 side is described in ). DHCPv4-over-DHCPv6 support is experimental and the details of the inter-process communication can change: both the DHCPv4 and DHCPv6 sides should be running the same version of Kea. The dhcp4o6-port global parameter specifies the first of the two consecutive ports of the UDP sockets used for the communication between the DHCPv6 and DHCPv4 servers (the DHCPv4 server is bound to ::1 on port + 1 and connected to ::1 on port). With DHCPv4-over-DHCPv6 the DHCPv4 server does not have access to several of the identifiers it would normally use to select a subnet. In order to address this issue three new configuration entires have been added. The presence of any of these allows the subnet to be used with DHCPv4-over-DHCPv6. These entries are: 4o6-subnet: Takes a prefix (i.e., an IPv6 address followed by a slash and a prefix length) which is matched against the source address. 4o6-interface-id: Takes a relay interface ID option value. 4o6-interface: Takes an interface name which is matched against the incoming interface name. The following configuration was used during some tests: { # DHCPv4 conf "Dhcp4": { "interfaces-config": { "interfaces": [ "eno33554984" ] }, "lease-database": { "type": "memfile", "name": "leases4" }, "valid-lifetime": 4000, "subnet4": [ { "subnet": "10.10.10.0/24", "4o6-interface": "eno33554984", "4o6-subnet": "2001:db8:1:1::/64", "pools": [ { "pool": "10.10.10.100 - 10.10.10.199" } ] } ], "dhcp4o6-port": 6767 }, "Logging": { "loggers": [ { "name": "kea-dhcp4", "output_options": [ { "output": "/tmp/kea-dhcp4.log" } ], "severity": "DEBUG", "debuglevel": 0 } ] } }
Host Reservation in DHCPv4 There are many cases where it is useful to provide a configuration on a per host basis. The most obvious one is to reserve a specific, static address for exclusive use by a given client (host) ‐ the returning client will receive the same address from the server every time, and other clients will generally not receive that address. Another example when the host reservations are applicable is when a host has specific requirements, e.g. a printer that needs additional DHCP options. Yet another possible use case is to define unique names for hosts. Note that there may be cases when the new reservation has been made for the client for the address being currently in use by another client. We call this situation a "conflict". The conflicts get resolved automatically over time as described in subsequent sections. Once the conflict is resolved, the client will keep receiving the reserved configuration when it renews. Host reservations are defined as parameters for each subnet. Each host has to be identified by an identifier, for example the hardware/MAC address. There is an optional reservations array in the Subnet4 element. Each element in that array is a structure that holds information about reservations for a single host. In particular, the structure has to have an identifier that uniquely identifies a host. In the DHCPv4 context, the identifier is usually a hardware or MAC address. In most cases an IP address will be specified. It is also possible to specify a hostname, host specific options or fields carried within DHCPv4 message such as siaddr, sname or file. In Kea 1.0.0 it was only possible to create host reservations using client's hardware address. Host reservations by client identifier, DUID and circuit-id have been added in Kea 1.1.0. The following example shows how to reserve addresses for specific hosts: "subnet4": [ { "pools": [ { "pool": "192.0.2.1 - 192.0.2.200" } ], "subnet": "192.0.2.0/24", "interface": "eth0", "reservations": [ { "hw-address": "1a:1b:1c:1d:1e:1f", "ip-address": "192.0.2.202" }, { "duid": "0a:0b:0c:0d:0e:0f", "ip-address": "192.0.2.100", "hostname": "alice-laptop" }, { "circuit-id": "'charter950'", "ip-address": "192.0.2.203" }, { "client-id": "01:11:22:33:44:55:66", "ip-address": "192.0.2.204" } ] } ] The first entry reserves the 192.0.2.202 address for the client that uses a MAC address of 1a:1b:1c:1d:1e:1f. The second entry reserves the address 192.0.2.100 and the hostname of alice-laptop for the client using a DUID 0a:0b:0c:0d:0e:0f. (Note that if you plan to do DNS updates, it is strongly recommended for the hostnames to be unique.) The third example reserves address 192.0.3.203 to a client whose request would be relayed by a relay agent that inserts a circuid-it option with the value 'charter950'. The fourth entry reserves address 192.0.2.204 for a client that uses a client identifier with value 01:11:22:33:44:55:66. The above example is used for ilustrational purposes only and in actual deployments it is recommended to use as few types as possible (preferably just one). See for a detailed discussion of this point. Making a reservation for a mobile host that may visit multiple subnets requires a separate host definition in each subnet it is expected to visit. It is not allowed to define multiple host definitions with the same hardware address in a single subnet. Multiple host definitions with the same hardware address are valid if each is in a different subnet. Adding host reservation incurs a performance penalty. In principle, when a server that does not support host reservation responds to a query, it needs to check whether there is a lease for a given address being considered for allocation or renewal. The server that also supports host reservation has to perform additional checks: not only if the address is currently used (i.e. if there is a lease for it), but also whether the address could be used by someone else (i.e. there is a reservation for it). That additional check incurs additional overhead.
Address Reservation Types In a typical scenario there is an IPv4 subnet defined, e.g. 192.0.2.0/24, with certain part of it dedicated for dynamic allocation by the DHCPv4 server. That dynamic part is referred to as a dynamic pool or simply a pool. In principle, a host reservation can reserve any address that belongs to the subnet. The reservations that specify addresses that belong to configured pools are called "in-pool reservations". In contrast, those that do not belong to dynamic pools are called "out-of-pool reservations". There is no formal difference in the reservation syntax and both reservation types are handled uniformly. However, upcoming releases may offer improved performance if there are only out-of-pool reservations as the server will be able to skip reservation checks when dealing with existing leases. Therefore, system administrators are encouraged to use out-of-pool reservations if possible.
Conflicts in DHCPv4 Reservations As the reservations and lease information are stored separately, conflicts may arise. Consider the following series of events. The server has configured the dynamic pool of addresses from the range of 192.0.2.10 to 192.0.2.20. Host A requests an address and gets 192.0.2.10. Now the system administrator decides to reserve address 192.0.2.10 for Host B. In general, reserving an address that is currently assigned to someone else is not recommended, but there are valid use cases where such an operation is warranted. The server now has a conflict to resolve. Let's analyze the situation here. If Host B boots up and requests an address, the server is not able to assign the reserved address 192.0.2.10. A naive approach would to be immediately remove the existing lease for the Host A and create a new one for the Host B. That would not solve the problem, though, because as soon as the Host B gets the address, it will detect that the address is already in use by the Host A and would send the DHCPDECLINE message. Therefore, in this situation, the server has to temporarily assign a different address (not matching what has been reserved) to the Host B. When Host A renews its address, the server will discover that the address being renewed is now reserved for another host - Host B. Therefore the server will inform the Host A that it is no longer allowed to use it by sending a DHCPNAK message. The server will not remove the lease, though, as there's small chance that the DHCPNAK may be lost if the network is lossy. If that happens, the client will not receive any responses, so it will retransmit its DHCPREQUEST packet. Once the DHCPNAK is received by Host A, it will revert to the server discovery and will eventually get a different address. Besides allocating a new lease, the server will also remove the old one. As a result, address 192.0.2.10 will become free . When Host B tries to renew its temporarily assigned address, the server will detect that it has a valid lease, but there is a reservation for a different address. The server will send DHCPNAK to inform Host B that its address is no longer usable, but will keep its lease (again, the DHCPNAK may be lost, so the server will keep it, until the client returns for a new address). Host B will revert to the server discovery phase and will eventually send a DHCPREQUEST message. This time the server will find out that there is a reservation for that host and the reserved address 192.0.2.10 is not used, so it will be granted. It will also remove the lease for the temporarily assigned address that Host B previously obtained. This recovery will succeed, even if other hosts will attempt to get the reserved address. Had the Host C requested address 192.0.2.10 after the reservation was made, the server will either offer a different address (when responding to DHCPDISCOVER) or would send DHCPNAK (when responding to DHCPREQUEST). This recovery mechanism allows the server to fully recover from a case where reservations conflict with the existing leases. This procedure takes time and will roughly take as long as the value set for of renew-timer. The best way to avoid such recovery is to not define new reservations that conflict with existing leases. Another recommendation is to use out-of-pool reservations. If the reserved address does not belong to a pool, there is no way that other clients could get this address.
Reserving a Hostname When the reservation for a client includes the hostname, the server will return this hostname to the client in the Client FQDN or Hostname options. The server responds with the Client FQDN option only if the client has included Client FQDN option in its message to the server. The server will respond with the Hostname option if the client included Hostname option in its message to the server or when the client requested Hostname option using Parameter Request List option. The server will return the Hostname option even if it is not configured to perform DNS updates. The reserved hostname always takes precedence over the hostname supplied by the client or the autogenerated (from the IPv4 address) hostname. The server qualifies the reserved hostname with the value of the qualifying-suffix parameter. For example, the following subnet configuration: { "subnet4": [ { "subnet": "10.0.0.0/24", "pools": [ { "pool": "10.0.0.10-10.0.0.100" } ], "reservations": [ { "hw-address": "aa:bb:cc:dd:ee:ff", "hostname": "alice-laptop" } ] }], "dhcp-ddns": { "enable-updates": true, "qualifying-suffix": "example.isc.org." } } will result in assigning the "alice-laptop.example.isc.org." hostname to the client using the MAC address "aa:bb:cc:dd:ee:ff". If the qualifying-suffix is not specified, the default (empty) value will be used, and in this case the value specified as a hostname will be treated as fully qualified name. Thus, by leaving the qualifying-suffix empty it is possible to qualify hostnames for the different clients with different domain names: { "subnet4": [ { "subnet": "10.0.0.0/24", "pools": [ { "pool": "10.0.0.10-10.0.0.100" } ], "reservations": [ { "hw-address": "aa:bb:cc:dd:ee:ff", "hostname": "alice-laptop.isc.org." }, { "hw-address": "12:34:56:78:99:AA", "hostname": "mark-desktop.example.org." } ] }], "dhcp-ddns": { "enable-updates": true, } }
Including Specific DHCPv4 Options in Reservations Kea 1.1.0 introduced the ability to specify options on a per host basis. The options follow the same rules as any other options. These can be standard options (see ), custom options (see ) or vendor specific options (see ). The following example demonstrates how standard options can be defined. { "subnet4": [ { "reservations": [ { "hw-address": "aa:bb:cc:dd:ee:ff", "ip-address": "192.0.2.1", "option-data": [ { "name": "cookie-servers", "data": "10.1.1.202,10.1.1.203" }, { "name": "log-servers", "data": "10.1.1.200,10.1.1.201" } ] } ] } ] } Vendor specific options can be reserved in a similar manner: { "subnet4": [ { "reservations": [ { "hw-address": "aa:bb:cc:dd:ee:ff", "ip-address": "10.0.0.7", "option-data": [ { "name": "vivso-suboptions", "data": "4491" }, { "name": "tftp-servers", "space": "vendor-4491", "data": "10.1.1.202,10.1.1.203" } ] } ] } ] } Options defined on host level have the highest priority. In other words, if there are options defined with the same type on global, subnet, class and host level, the host specific values will be used.
Reserving Next Server, Server Hostname and Boot File Name BOOTP/DHCPv4 messages include "siaddr", "sname" and "file" fields. Even though, DHCPv4 includes corresponding options, such as option 66 and option 67, some clients may not support these options. For this reason, server administrators often use the "siaddr", "sname" and "file" fields instead. With Kea, it is possible to make static reservations for these DHCPv4 message fields: { "subnet4": [ { "reservations": [ { "hw-address": "aa:bb:cc:dd:ee:ff", "next-server": "10.1.1.2", "server-hostname": "server-hostname.example.org", "boot-file-name": "/tmp/bootfile.efi" } ] } ] } Note that those parameters can be specified in combination with other parameters for a reservation, e.g. reserved IPv4 address. These parameters are optional, i.e. a subset of them can specified, or all of them can be omitted.
Reserving Client Classes in DHCPv4 explains how to configure the server to assign classes to a client based on the content of the options that this client sends to the server. Host reservations mechanisms also allow for statically assigning classes to the clients. The definitions of these classes must exist in the Kea configuration. The following configuration snippet shows how to specify that a client belongs to classes reserved-class1 and reserved-class2. Those classes are associated with specific options being sent to the clients which belong to them. { "client-classes": [ { "name": "reserved-class1", "option-data": [ { "name": "routers", "data": "10.0.0.200" } ] }, { "name": "reserved-class2", "option-data": [ { "name": "domain-name-servers", "data": "10.0.0.201" } ] } ], "subnet4": [ { "subnet": "10.0.0.0/24", "pools": [ { "pool": "10.0.0.10-10.0.0.100" } ], "reservations": [ { "hw-address": "aa:bb:cc:dd:ee:ff", "client-classes": [ "reserved-class1", "reserved-class2" ] } ] } ] } Static class assignments, as shown above, can be used in conjuction with classification using expressions.
Storing Host Reservations in MySQL or PostgreSQL It is possible to store host reservations in MySQL or PostgreSQL database. See for information on how to configure Kea to use reservations stored in MySQL or PostgreSQL. Kea does not provide any dedicated tools for managing reservations in a database. The Kea wiki provides detailed information and examples of how reservations can be inserted into the database. In Kea 1.1.0 maximum length of an option specified per host is arbitrarily set to 4096 bytes.
Storing host reservations in CQL (Cassandra) Kea currently does not support storing reservations in Cassandra (CQL).
Fine Tuning DHCPv4 Host Reservation The host reservation capability introduces additional restrictions for the allocation engine (the component of Kea that selects an address for a client) during lease selection and renewal. In particular, three major checks are necessary. First, when selecting a new lease, it is not sufficient for a candidate lease to not be used by another DHCP client. It also must not be reserved for another client. Second, when renewing a lease, additional check must be performed whether the address being renewed is not reserved for another client. Finally, when a host renews an address, the server has to check whether there is a reservation for this host, so the existing (dynamically allocated) address should be revoked and the reserved one be used instead. Some of those checks may be unnecessary in certain deployments and not performing them may improve performance. The Kea server provides the reservation-mode configuration parameter to select the types of reservations allowed for the particular subnet. Each reservation type has different constraints for the checks to be performed by the server when allocating or renewing a lease for the client. Allowed values are: all - enables all host reservation types. This is the default value. This setting is the safest and the most flexible. It allows in-pool and out-of-pool reservations. As all checks are conducted, it is also the slowest. out-of-pool - allows only out of pool host reservations. With this setting in place, the server may assume that all host reservations are for addresses that do not belong to the dynamic pool. Therefore it can skip the reservation checks when dealing with in-pool addresses, thus improving performance. Do not use this mode if any of your reservations use in-pool address. Caution is advised when using this setting: Kea 1.1.0 does not sanity check the reservations against reservation-mode and misconfiguration may cause problems. disabled - host reservation support is disabled. As there are no reservations, the server will skip all checks. Any reservations defined will be completely ignored. As the checks are skipped, the server may operate faster in this mode. An example configuration that disables reservation looks like follows: "Dhcp4": { "subnet4": [ { "subnet": "192.0.2.0/24", "reservation-mode": "disabled", ... } ] } Another aspect of the host reservations are the different types of identifiers. Kea 1.1.0 supports four types of identifiers (hw-address, duid, client-id and circuit-id), but more identifier types are likely to be added in the future. This is beneficial from a usability perspective. However, there is a drawback. For each incoming packet Kea has to to extract each identifier type and then query the database to see if there is a reservation done by this particular identifier. If nothing is found, the next identifier is extracted and the next query is issued. This process continues until either a reservation is found or all identifier types have been checked. Over time with an increasing number of supported identifier types, Kea would become slower and slower. To address this problem, a parameter called host-reservation-identifiers has been introduced. It takes a list of identifier types as a parameter. Kea will check only those identifier types enumerated in host-reservation-identifiers. From a performance perspective the number of identifier types should be kept to a minimum, ideally limited to one. If your deployment uses several reservation types, please enumerate them from most to least frequently used as this increases the chances of Kea finding the reservation using the fewest number of queries. An example of host reservation identifiers looks as follows: "host-reservation-identifiers": [ "circuit-id", "hw-address", "duid", "client-id" ], "subnet4": [ { "subnet": "192.0.2.0/24", ... } ] If not specified, the default value is: "host-reservation-identifiers": [ "hw-address", "duid", "circuit-id", "client-id" ]
Server Identifier in DHCPv4 The DHCPv4 protocol uses a "server identifier" to allow clients to discriminate between several servers present on the same link: this value is an IPv4 address of the server. The server chooses the IPv4 address of the interface on which the message from the client (or relay) has been received. A single server instance will use multiple server identifiers if it is receiving queries on multiple interfaces. Currently there is no mechanism to override the default server identifiers by an administrator. In the future, the configuration mechanism will be used to specify the custom server identifier.
How the DHCPv4 Server Selects a Subnet for the Client The DHCPv4 server differentiates between the directly connected clients, clients trying to renew leases and clients sending their messages through relays. For directly connected clients, the server will check the configuration for the interface on which the message has been received and, if the server configuration doesn't match any configured subnet, the message is discarded. Assuming that the server's interface is configured with the IPv4 address 192.0.2.3, the server will only process messages received through this interface from a directly connected client if there is a subnet configured to which this IPv4 address belongs, e.g. 192.0.2.0/24. The server will use this subnet to assign IPv4 address for the client. The rule above does not apply when the client unicasts its message, i.e. is trying to renew its lease. Such a message is accepted through any interface. The renewing client sets ciaddr to the currently used IPv4 address. The server uses this address to select the subnet for the client (in particular, to extend the lease using this address). If the message is relayed it is accepted through any interface. The giaddr set by the relay agent is used to select the subnet for the client. It is also possible to specify a relay IPv4 address for a given subnet. It can be used to match incoming packets into a subnet in uncommon configurations, e.g. shared subnets. See for details. The subnet selection mechanism described in this section is based on the assumption that client classification is not used. The classification mechanism alters the way in which a subnet is selected for the client, depending on the classes to which the client belongs.
Using a Specific Relay Agent for a Subnet A relay has to have an interface connected to the link on which the clients are being configured. Typically the relay has an IPv4 address configured on that interface that belongs to the subnet from which the server will assign addresses. In the typical case, the server is able to use the IPv4 address inserted by the relay (in the giaddr field of the DHCPv4 packet) to select the appropriate subnet. However, that is not always the case. In certain uncommon — but valid — deployments, the relay address may not match the subnet. This usually means that there is more than one subnet allocated for a given link. The two most common examples where this is the case are long lasting network renumbering (where both old and new address space is still being used) and a cable network. In a cable network both cable modems and the devices behind them are physically connected to the same link, yet they use distinct addressing. In such a case, the DHCPv4 server needs additional information (the IPv4 address of the relay) to properly select an appropriate subnet. The following example assumes that there is a subnet 192.0.2.0/24 that is accessible via a relay that uses 10.0.0.1 as its IPv4 address. The server will be able to select this subnet for any incoming packets that came from a relay that has an address in 192.0.2.0/24 subnet. It will also select that subnet for a relay with address 10.0.0.1. "Dhcp4": { "subnet4": [ { "subnet": "192.0.2.0/24", "pools": [ { "pool": "192.0.2.10 - 192.0.2.20" } ], "relay": { "ip-address": "10.0.0.1" }, ... } ], ... }
Segregating IPv4 Clients in a Cable Network In certain cases, it is useful to mix relay address information, introduced in with client classification, explained in . One specific example is cable network, where typically modems get addresses from a different subnet than all devices connected behind them. Let us assume that there is one CMTS (Cable Modem Termination System) with one CM MAC (a physical link that modems are connected to). We want the modems to get addresses from the 10.1.1.0/24 subnet, while everything connected behind modems should get addresses from another subnet (192.0.2.0/24). The CMTS that acts as a relay uses address 10.1.1.1. The following configuration can serve that configuration: "Dhcp4": { "subnet4": [ { "subnet": "10.1.1.0/24", "pools": [ { "pool": "10.1.1.2 - 10.1.1.20" } ], "client-class" "docsis3.0", "relay": { "ip-address": "10.1.1.1" } }, { "subnet": "192.0.2.0/24", "pools": [ { "pool": "192.0.2.10 - 192.0.2.20" } ], "relay": { "ip-address": "10.1.1.1" } } ], ... }
Duplicate Addresses (DHCPDECLINE Support) The DHCPv4 server is configured with a certain pool of addresses that it is expected to hand out to the DHCPv4 clients. It is assumed that the server is authoritative and has complete jurisdiction over those addresses. However, due to various reasons, such as misconfiguration or a faulty client implementation that retains its address beyond the valid lifetime, there may be devices connected that use those addresses without the server's approval or knowledge. Such an unwelcome event can be detected by legitimate clients (using ARP or ICMP Echo Request mechanisms) and reported to the DHCPv4 server using a DHCPDECLINE message. The server will do a sanity check (if the client declining an address really was supposed to use it), and then will conduct a clean up operation. Any DNS entries related to that address will be removed, the fact will be logged and hooks will be triggered. After that is done, the address will be marked as declined (which indicates that it is used by an unknown entity and thus not available for assignment to anyone) and a probation time will be set on it. Unless otherwise configured, the probation period lasts 24 hours. After that period, the server will recover the lease (i.e. put it back into the available state) and the address will be available for assignment again. It should be noted that if the underlying issue of a misconfigured device is not resolved, the duplicate address scenario will repeat. On the other hand, it provides an opportunity to recover from such an event automatically, without any sysadmin intervention. To configure the decline probation period to a value other than the default, the following syntax can be used: "Dhcp4": { "decline-probation-period": 3600, "subnet4": [ ... ], ... } The parameter is expressed in seconds, so the example above will instruct the server to recycle declined leases after an hour. There are several statistics and hook points associated with the Decline handling procedure. The lease4_decline hook is triggered after the incoming DHCPDECLINE message has been sanitized and the server is about to decline the lease. The declined-addresses statistic is increased after the hook returns (both global and subnet specific variants). (See and for more details on DHCPv4 statistics and Kea hook points.) Once the probation time elapses, the declined lease is recovered using the standard expired lease reclamation procedure, with several additional steps. In particular, both declined-addresses statistics (global and subnet specific) are decreased. At the same time, reclaimed-declined-addresses statistics (again in two variants, global and subnet specific) are increased. Note about statistics: The server does not decrease the assigned-addresses statistics when a DHCPDECLINE is received and processed successfully. While technically a declined address is no longer assigned, the primary usage of the assigned-addresses statistic is to monitor pool utilization. Most people would forget to include declined-addresses in the calculation, and simply do assigned-addresses/total-addresses. This would have a bias towards under-representing pool utilization. As this has a potential for major issues, we decided not to decrease assigned addresses immediately after receiving DHCPDECLINE, but to do it later when we recover the address back to the available pool.
Statistics in the DHCPv4 Server This section describes DHCPv4-specific statistics. For a general overview and usage of statistics, see . The DHCPv4 server supports the following statistics: DHCPv4 Statistics Statistic Data Type Description pkt4-received integer Number of DHCPv4 packets received. This includes all packets: valid, bogus, corrupted, rejected etc. This statistic is expected to grow rapidly. pkt4-discover-received integer Number of DHCPDISCOVER packets received. This statistic is expected to grow. Its increase means that clients that just booted started their configuration process and their initial packets reached your server. pkt4-offer-received integer Number of DHCPOFFER packets received. This statistic is expected to remain zero at all times, as DHCPOFFER packets are sent by the server and the server is never expected to receive them. Non-zero value indicates an error. One likely cause would be a misbehaving relay agent that incorrectly forwards DHCPOFFER messages towards the server, rather back to the clients. pkt4-request-received integer Number of DHCPREQUEST packets received. This statistic is expected to grow. Its increase means that clients that just booted received server's response (DHCPOFFER), accepted it and now requesting an address (DHCPREQUEST). pkt4-ack-received integer Number of DHCPACK packets received. This statistic is expected to remain zero at all times, as DHCPACK packets are sent by the server and the server is never expected to receive them. Non-zero value indicates an error. One likely cause would be a misbehaving relay agent that incorrectly forwards DHCPACK messages towards the server, rather back to the clients. pkt4-nak-received integer Number of DHCPNAK packets received. This statistic is expected to remain zero at all times, as DHCPNAK packets are sent by the server and the server is never expected to receive them. Non-zero value indicates an error. One likely cause would be a misbehaving relay agent that incorrectly forwards DHCPNAK messages towards the server, rather back to the clients. pkt4-release-received integer Number of DHCPRELEASE packets received. This statistic is expected to grow. Its increase means that clients that had an address are shutting down or stop using their addresses. pkt4-decline-received integer Number of DHCPDECLINE packets received. This statistic is expected to remain close to zero. Its increase means that a client that leased an address, but discovered that the address is currently used by an unknown device in your network. pkt4-inform-received integer Number of DHCPINFORM packets received. This statistic is expected to grow. Its increase means that there are clients that either do not need an address or already have an address and are interested only in getting additional configuration parameters. pkt4-unknown-received integer Number of packets received of an unknown type. Non-zero value of this statistic indicates that the server received a packet that it wasn't able to recognize: either with unsupported type or possibly malformed (without message type option). pkt4-sent integer Number of DHCPv4 packets sent. This statistic is expected to grow every time the server transmits a packet. In general, it should roughly match pkt4-received, as most incoming packets cause server to respond. There are exceptions (e.g. DHCPRELEASE), so do not worry, if it is lesser than pkt4-received. pkt4-offer-sent integer Number of DHCPOFFER packets sent. This statistic is expected to grow in most cases after a DHCPDISCOVER is processed. There are certain uncommon, but valid cases where incoming DHCPDISCOVER is dropped, but in general this statistic is expected to be close to pkt4-discover-received. pkt4-ack-sent integer Number of DHCPACK packets sent. This statistic is expected to grow in most cases after a DHCPREQUEST is processed. There are certain cases where DHCPNAK is sent instead. In general, the sum of pkt4-ack-sent and pkt4-nak-sent should be close to pkt4-request-received. pkt4-nak-sent integer Number of DHCPNAK packets sent. This statistic is expected to grow when the server chooses to not honor the address requested by a client. In general, the sum of pkt4-ack-sent and pkt4-nak-sent should be close to pkt4-request-received. pkt4-parse-failed integer Number of incoming packets that could not be parsed. A non-zero value of this statistic indicates that the server received malformed or truncated packet. This may indicate problems in your network, faulty clients or a bug in the server. pkt4-receive-drop integer Number of incoming packets that were dropped. The exact reason for dropping packets is logged, but the most common reasons may be: an unacceptable packet type, direct responses are forbidden, or the server-id sent by the client does not match the server's server-id. subnet[id].total-addresses integer The total number of addresses available for DHCPv4 management. In other words, this is the sum of all addresses in all configured pools. This statistic changes only during configuration changes. Note it does not take into account any addresses that may be reserved due to host reservation. The id is the subnet-id of a given subnet. This statistic is exposed for each subnet separately. This statistic is reset during reconfiguration event. subnet[id].assigned-addresses integer This statistic shows the number of assigned addresses in a given subnet. It increases every time a new lease is allocated (as a result of receiving a DHCPREQUEST message) and is decreased every time a lease is released (a DHCPRELEASE message is received) or expires. The id is the subnet-id of the subnet. This statistic is exposed for each subnet separately. This statistic is reset during reconfiguration event. declined-addresses integer This statistic shows the number of IPv4 addresses that are currently declined, so counting the number of leases currently unavailable. Once a lease is recovered, this statistic will be decreased. Ideally, this statistic should be zero. If this statistic is non-zero (or worse increasing), a network administrator should investigate if there is a misbehaving device in his network. This is a global statistic that covers all subnets. subnet[id].declined-addresses integer This statistic shows the number of IPv4 addresses that are currently declined in a given subnet, so is a count of the number of leases currently unavailable. Once a lease is recovered, this statistic will be decreased. Ideally, this statistic should be zero. If this statistic is non-zero (or worse increasing), a network administrator should investigate if there is a misbehaving device in his network. The id is the subnet-id of a given subnet. This statistic is exposed for each subnet separately. reclaimed-declined-addresses integer This statistic shows the number of IPv4 addresses that were declined, but have now been recovered. Unlike declined-addresses, this statistic never decreases. It can be used as a long term indicator of how many actual valid Declines were processed and recovered from. This is a global statistic that covers all subnets. subnet[id].reclaimed-declined-addresses integer This statistic shows the number of IPv4 addresses that were declined, but have now been recovered. Unlike declined-addresses, this statistic never decreases. It can be used as a long term indicator of how many actual valid Declines were processed and recovered from. The id is the subnet-id of a given subnet. This statistic is exposed for each subnet separately.
Management API for the DHCPv4 Server The management API allows the issuing of specific management commands, such as statistics retrieval, reconfiguration or shutdown. For more details, see . Currently the only supported communication channel type is UNIX stream socket. By default there are no sockets open. To instruct Kea to open a socket, the following entry in the configuration file can be used: "Dhcp4": { "control-socket": { "socket-type": "unix", "socket-name": "/path/to/the/unix/socket" }, "subnet4": [ ... ], ... } The length of the path specified by the socket-name parameter is restricted by the maximum length for the unix socket name on your operating system, i.e. the size of the sun_path field in the sockaddr_un structure, decreased by 1. This value varies on different operating systems between 91 and 107 characters. Typical values are 107 on Linux and 103 on FreeBSD. Communication over control channel is conducted using JSON structures. See the Control Channel section in the Kea Developer's Guide for more details. The DHCPv4 server supports statistic-get, statistic-reset, statistic-remove, statistic-get-all, statistic-reset-all and statistic-remove-all, specified in . It also supports list-commands and shutdown, specified in and , respectively.
Supported DHCP Standards The following standards are currently supported: Dynamic Host Configuration Protocol, RFC 2131: Supported messages are DHCPDISCOVER (1), DHCPOFFER (2), DHCPREQUEST (3), DHCPRELEASE (7), DHCPINFORM (8), DHCPACK (5), and DHCPNAK(6). DHCP Options and BOOTP Vendor Extensions, RFC 2132: Supported options are: PAD (0), END(255), Message Type(53), DHCP Server Identifier (54), Domain Name (15), DNS Servers (6), IP Address Lease Time (51), Subnet mask (1), and Routers (3). DHCP Relay Agent Information Option, RFC 3046: Relay Agent Information option is supported. Vendor-Identifying Vendor Options for Dynamic Host Configuration Protocol version 4, RFC 3925: Vendor-Identifying Vendor Class and Vendor-Identifying Vendor-Specific Information options are supported. Client Identifier Option in DHCP Server Replies, RFC 6842: Server by default sends back client-id option. That capability may be disabled. See for details.
DHCPv4 Server Limitations These are the current limitations of the DHCPv4 server software. Most of them are reflections of the current stage of development and should be treated as not implemented yet, rather than actual limitations. However, some of them are implications of the design choices made. Those are clearly marked as such. BOOTP (RFC 951) is not supported. This is a design choice: BOOTP support is not planned. On Linux and BSD system families the DHCP messages are sent and received over the raw sockets (using LPF and BPF) and all packet headers (including data link layer, IP and UDP headers) are created and parsed by Kea, rather than the system kernel. Currently, Kea can only parse the data link layer headers with a format adhering to IEEE 802.3 standard and assumes this data link layer header format for all interfaces. Hence, Kea will fail to work on interfaces which use different data link layer header formats (e.g. Infiniband). The DHCPv4 server does not verify that assigned address is unused. According to RFC 2131, the allocating server should verify that address is not used by sending ICMP echo request.
kea-1.1.0/doc/guide/lease-expiration.xml0000664000175000017500000003620412772445242015047 00000000000000 ]> Lease Expiration in DHCPv4 and DHCPv6 The primary role of the DHCP server is to assign addresses and/or delegate prefixes to DHCP clients. These addresses and prefixes are often referred to as "leases". Leases are typically assigned to clients for a finite amount of time, known as the "valid lifetime". DHCP clients who wish to continue using their assigned leases, will periodically renew them by sending the appropriate message to the DHCP server. The DHCP server records the time when these leases are renewed and calculates new expiration times for them. If the client does not renew a lease before its valid lifetime elapses, the lease is considered expired. There are many situations when the client may cease lease renewals. A common scenario is when the machine running the client shuts down for an extended period of time. The process through which the DHCP server makes expired leases available for reassignment is referred to as "lease reclamation" and expired leases returned to availability through this process are referred to as "reclaimed". The DHCP server attempts to reclaim an expired lease as soon as it detects that it has expired. One way in which the server detects expiration occurs when it is trying to allocate a lease to a client and finds this lease already present in the database but expired. Another way is by periodically querying the lease database for them. Regardless of how an expired lease is detected, before it may assigned to a client, it must be reclaimed. This chapter explains how to configure the server to periodically query for the expired leases and how to minimize the impact of the periodic lease reclamation process on the server's responsiveness. Finally, it explains "lease affinity", which provides the means to assign the same lease to a returning client after its lease has expired. Although, all configuration examples in this section are provided for the DHCPv4 server, the same parameters may be used for the DHCPv6 server configuration.
Lease Reclamation Lease reclamation is the process through which an expired lease becomes available for assignment to the same or different client. This process involves the following steps for each reclaimed lease: Invoke callouts for the lease4_expire or lease6_expire hook points if hook libraries supporting those callouts are currently loaded. Update DNS, i.e. remove any DNS entries associated with the expired lease. Update lease information in the lease database to indicate that the lease is now available for re-assignment. Update counters on the server, which includes increasing the number of reclaimed leases and decreasing the number of assigned addresses or delegated prefixes. Please refer to to see how to configure DNS updates in Kea, and to for information about using hooks libraries.
Configuring Lease Reclamation Kea can be configured to periodically detect and reclaim expired leases. During this process the lease entries in the database are modified or removed. While this is happening the server will not process incoming DHCP messages to avoid issues with concurrent access to database information. As a result, the server will be unresponsive while lease reclamation is performed and DHCP queries will accumulate; responses will be sent once the leases reclamation cycle is complete. In deployments where response time is critical, administrators may wish to minimize the interruptions in service caused by lease reclamation. Toward this end, Kea provides configuration parameters to control: the frequency of lease reclamation cycles, the maximum number of leases processed in a single reclamation cycle, and the maximum amount of time a single reclamation cycle is allowed to run before being interrupted. The following examples demonstrate how these parameters can be used: "Dhcp4": { ... "expired-leases-processing": { "reclaim-timer-wait-time": 5, "max-reclaim-leases": 0, "max-reclaim-time": 0, "flush-reclaimed-timer-wait-time": 0, }, ... } The first parameter is expressed in seconds and specifies an interval between the two consecutive lease reclamation cycles. This is explained by the following diagram. | c1 | | c2 | |c3| | c4 | |<---->|<---------->|<-->|<---------->|<>|<---------->|<-->| ----------------------------------------------------------------> | | 5s | | 5s | | 5s | | time This diagram shows four lease reclamation cycles (c1 through c4) of variable duration. Note that the duration of the reclamation cycle depends on the number of expired leases detected and processed in the particular cycle. This duration is also usually significantly shorter than the interval between the cycles. According to the reclaim-timer-wait-time the server keeps fixed intervals of five seconds between the end of one cycle and the start of the next cycle. This guarantees the presence of 5s long periods during which the server remains responsive to DHCP queries and does not perform lease reclamation. The max-reclaim-leases and max-reclaim-time are set to 0, which sets no restriction on the maximum number of leases reclaimed in the particular cycle, or on the maximum duration of each cycle. In deployments with high lease pool utilization, relatively short valid lifetimes, and frequently disconnecting clients which allow leases to expire, the number of expired leases requiring reclamation at any given time may rise significantly. In this case it is often desirable to apply restrictions on the maximum duration of a reclamation cycle or the maximum number of leases reclaimed in a cycle. The following configuration demonstrates how this can be done: "Dhcp4": { ... "expired-leases-processing": { "reclaim-timer-wait-time": 3, "max-reclaim-leases": 100, "max-reclaim-time": 50, "unwarned-reclaim-cycles": 10, }, ... } The max-reclaim-leases parameter limits the number of leases reclaimed in a single cycle to 100. The max-reclaim-time limits the maximum duration of each cycle to 50ms. The lease reclamation cycle will be interrupted if either of these limitations is reached. The reclamation of all unreclaimed leases will be attempted in subsequent cycles. The following diagram illustrates the behavior of the system in the presence of many expired leases, when the limits are applied for the reclamation cycles. | c1 | | c2 | | c3 | | c4 | |<-->|<-------------->|<-->|<-------------->|<-->|<-------------->|<-->|<-- ------------------------------------------------------------------------------> |50ms| 3s |50ms| 3s |50ms| 3s |50ms| time The diagram demonstrates the case when each reclamation cycle would take more than 50ms, and thus is interrupted according to the value of the max-reclaim-time. This results in equal durations of all reclamation cycles over time. Note that in this example the limitation of maximum 100 leases is not reached. This may be the case when database transactions are slow or callouts in the hook libraries attached to the server are slow. Regardless, the choosing values for either the maximum number of leases or a maximum cycle time strongly depends on the particular deployment, lease database backend being used, and any hooks libraries etc. Administrators may need to experiment to tune the system to suit the dynamics of their deployment. It is important to realize that with the use of these limits, there is a risk that expired leases will accumulate faster than the server can reclaim them. This should not be the problem if the server is dealing with a temporary burst of expirations, because it should be able to eventually deal with them over time. However, if leases expire at a high rate for a longer period of time, the unreclaimed leases will pile up in the database. In order to notify the administrator that the current configuration does not satisfy the needs for reclamation of expired leases, the server issues a warning message in the log if it was unable to reclaim all leases within the last couple of reclamation cycles. The number of cycles after which such warning is issued is specified with the unwarned-reclaim-cycles configuration parameter. Setting the reclaim-timer-wait-time to 0 disables periodic reclamation of the expired leases.
Configuring Lease Affinity Suppose that a laptop goes to a sleep mode after a period of user inactivity. While the laptop is in sleep mode, its DHCP client will not renew leases obtained from the server and these leases will eventually expire. When the laptop wakes up, it is often desirable for it to continue using its previous assigned IP addresses. In order to facilitate this, the server needs to correlate returning clients with their expired leases When the client returns, the server will first check for those leases and re-assign them if they have not been assigned to another client. The ability of the server to re-assign the same lease to a returning client is referred to as "lease affinity". When lease affinity is enabled, the server will still reclaim leases according to the parameters described in , but the reclaimed leases will be held in the database (rather than removed) for the specified amount of time. When the client returns, the server will first check if there are any reclaimed leases associated with this client and re-assign them if possible. However, it is important to note that any reclaimed lease may be assigned to another client if that client specifically asks for it. Therefore, the lease affinity does not guarantee that the reclaimed lease will be available for the client who used it before; it merely increases the chances for the client to be assigned the same lease. If the lease pool is small (this mostly applies to DHCPv4 for which address space is small), there is an increased likelihood that the expired lease will be assigned to another client. Consider the following configuration: "Dhcp4": { ... "expired-leases-processing": { "reclaim-timer-wait-time": 3, "hold-reclaimed-time": 1800, "flush-reclaimed-timer-wait-time": 5 }, ... } The hold-reclaim-time specifies how many seconds after an expiration a reclaimed lease should be held in the database for re-assignment to the same client. In the example given above, reclaimed leases will be held for 30 minutes (1800s) after their expiration. During this time, the server will likely be able to re-assign the same lease to the returning client, unless another client requests this lease and the server assigns it. The server must periodically remove reclaimed leases for which the time indicated by hold-reclaim-time has elapsed. The flush-reclaimed-timer-wait-time controls how often the server removes such leases. In the example provided above, the server will initiate removal of such leases 5 seconds after the previous removal attempt was completed. Setting this value to 0 disables lease affinity, in which case leases will be removed from the lease database when they are reclaimed. If lease affinity is enabled, it is recommended that hold-reclaim-time be set to a value significantly higher than the reclaim-timer-wait-time, as timely removal of expired-reclaimed leases is less critical while the removal process may impact server responsiveness.
Default Configuration Values for Leases Reclamation The following list presents all configuration parameters pertaining to processing expired leases with their default values: reclaim-timer-wait-time = 10 [seconds] flush-reclaimed-timer-wait-time = 25 [seconds] hold-reclaimed-time = 3600 [seconds] max-reclaim-leases = 100 max-reclaim-time = 250 [milliseconds] unwarned-reclaim-cycles = 5 The default value for any parameter is used when this parameter not explicitly specified in the configuration. Also, the expired-leases-processing map may be omitted entirely in the configuration, in which case the default values are used for all parameters listed above.
Reclaiming Expired Leases with Command The leases-reclaim command can be used to trigger leases reclamation at any time. Please consult the for the details about using this command.
kea-1.1.0/doc/guide/stats.xml0000664000175000017500000002535212772445242012736 00000000000000 ]> Statistics
Statistics Overview Both Kea DHCP servers support statistics gathering. A working DHCP server encounters various events that can cause certain statistics to be collected. For example, a DHCPv4 server may receive a packet (pkt4-received statistic increases by one) that after parsing was identified as a DHCPDISCOVER (pkt4-discover-received). The Server processed it and decided to send a DHCPOFFER representing its answer (pkt4-offer-sent and pkt4-sent statistics increase by one). Such events happen frequently, so it is not uncommon for the statistics to have values in high thousands. They can serve as an easy and powerful tool for observing a server's and network's health. For example, if pkt4-received statistic stops growing, it means that the clients' packets are not reaching the server. There are four types of statistics: integer - this is the most common type. It is implemented as 64 bit integer (int64_t in C++), so it can hold any value between -2^63 to 2^63 -1. floating point - this type is intended to store floating point precision. It is implemented as double C++ type. duration - this type is intended for recording time periods. It uses boost::posix_time::time_duration type, which stores hours, minutes, seconds and microseconds. string - this type is intended for recording statistics in textual form. It uses std::string C++ type. During normal operation, DHCPv4 and DHCPv6 servers gather statistics. For a list of DHCPv4 and DHCPv6 statistics, see and , respectively. To extract data from the statistics module, the control channel can be used. See for details. It is possible to retrieve a single or all statistics, reset statistics (i.e. set to neutral value, typically zero) or even remove completely a single or all statistics. See section for a list of statistic oriented commands.
Statistics Lifecycle It is useful to understand how the Statistics Manager module works. When the server starts operation, the manager is empty and does not have any statistics. When statistic-get-all is executed, an empty list is returned. Once the server performs an operation that causes a statistic to change, the related statistic will be created. In the general case, once a statistic is recorded even once, it is kept in the manager, until explicitly removed, by statistic-remove or statistic-remove-all being called or the server is shut down. Per subnet statistics are explicitly removed when reconfiguration takes place. Statistics are considered run-time properties, so they are not retained after server restart. Removing a statistic that is updated frequently makes little sense as it will be re-added when the server code next records that statistic. The statistic-remove and statistic-remove-all commands are intended to remove statistics that are not expected to be observed in the near future. For example, a misconfigured device in a network may cause clients to report duplicate addresses, so the server will report increasing values of pkt4-decline-received. Once the problem is found and the device is removed, the system administrator may want to remove the pkt4-decline-received statistic, so it won't be reported anymore. If a duplicate address is detected ever again, the server will add this statistic back.
Commands for Manipulating Statistics There are several commands defined that can be used for accessing (-get), resetting to zero or neutral value (-reset) or even removing a statistic completely (-remove). The difference between reset and remove is somewhat subtle. The reset command sets the value of the statistic to zero or neutral value. After this operation, the statistic will have a value of 0 (integer), 0.0 (float), 0h0m0s0us (duration) or "" (string). When asked for, a statistic with the values mentioned will be returned. Remove removes a statistic completely, so the statistic will not be reported anymore. Please note that the server code may add it back if there's a reason to record it. The following sections describe commands that can be sent to the server: the examples are not fragments of a configuration file. For more information on sending commands to Kea, see .
statistic-get command statistic-get command retrieves a single statistic. It takes a single string parameter called name that specifies the statistic name. An example command may look like this: { "command": "statistic-get", "arguments": { "name": "pkt4-received" } } The server will respond with details of the requested statistic, with result set to 0 indicating success and the specified statistic as the value of "arguments" parameter. If the requested statistic is not found, the response will contain an empty map, i.e. only { } as argument, but the status code will still be set to success (0).
statistic-reset command statistic-reset command sets the specified statistic to its neutral value: 0 for integer, 0.0 for float, 0h0m0s0us for time duration and "" for string type. It takes a single string parameter called name that specifies the statistic name. An example command may look like this: { "command": "statistic-reset", "arguments": { "name": "pkt4-received" } } If the specific statistic is found and reset was successful, the server will respond with a status of 0, indicating success and an empty parameters field. If an error is encountered (e.g. requested statistic was not found), the server will return a status code of 1 (error) and the text field will contain the error description.
statistic-remove command statistic-remove command attempts to delete a single statistic. It takes a single string parameter called name that specifies the statistic name. An example command may look like this: { "command": "statistic-remove", "arguments": { "name": "pkt4-received" } } If the specific statistic is found and its removal was successful, the server will respond with a status of 0, indicating success and an empty parameters field. If an error is encountered (e.g. requested statistic was not found), the server will return a status code of 1 (error) and the text field will contain the error description.
statistic-get-all command statistic-get-all command retrieves all statistics recorded. An example command may look like this: { "command": "statistic-get-all", "arguments": { } } The server will respond with details of all recorded statistics, with result set to 0 indicating that it iterated over all statistics (even when the total number of statistics is zero).
statistic-reset-all command statistic-reset command sets all statistics to their neutral values: 0 for integer, 0.0 for float, 0h0m0s0us for time duration and "" for string type. An example command may look like this: { "command": "statistic-reset-all", "arguments": { } } If the operation is successful, the server will respond with a status of 0, indicating success and an empty parameters field. If an error is encountered, the server will return a status code of 1 (error) and the text field will contain the error description.
statistic-remove-all command statistic-remove-all command attempts to delete all statistics. An example command may look like this: { "command": "statistic-remove-all", "arguments": { } } If the removal of all statistics was successful, the server will respond with a status of 0, indicating success and an empty parameters field. If an error is encountered, the server will return a status code of 1 (error) and the text field will contain the error description.
kea-1.1.0/doc/guide/libdhcp.xml0000664000175000017500000000374312772445242013205 00000000000000 ]> The libdhcp++ Library libdhcp++ is a library written in C++ that handles many DHCP-related tasks, including: DHCPv4 and DHCPv6 packets parsing, manipulation and assembly Option parsing, manipulation and assembly Network interface detection Socket operations such as creation, data transmission and reception and socket closing. While this library is currently used by Kea, it is designed to be a portable, universal library, useful for any kind of DHCP-related software.
Interface detection and Socket handling Both the DHCPv4 and DHCPv6 components share network interface detection routines. Interface detection is currently supported on Linux, all BSD family (FreeBSD, NetBSD, OpenBSD), Mac OS X and Solaris 11 systems. DHCPv4 requires special raw socket processing to send and receive packets from hosts that do not have IPv4 address assigned. Support for this operation is implemented on Linux, FreeBSD, NetBSD and OpenBSD. It is likely that DHCPv4 component will not work in certain cases on other systems.
kea-1.1.0/doc/guide/intro.xml0000664000175000017500000001505712772445242012734 00000000000000 %version; ]> Introduction Kea is the next generation of DHCP software developed by ISC. It supports both DHCPv4 and DHCPv6 protocols along with their extensions, e.g. prefix delegation and dynamic updates to DNS. Kea was initially developed as a part of the BIND 10 framework. In early 2014, ISC made the decision to discontinue active development of BIND 10 and continue development of Kea as standalone DHCP software. This guide covers Kea version &__VERSION__;.
Supported Platforms Kea is officially supported on Red Hat Enterprise Linux, CentOS, Fedora and FreeBSD systems. It is also likely to work on many other platforms: Kea 1.1.0 builds have been tested on (in no particular order) Red Hat Enteprise Linux 6.4, Debian GNU/Linux 7, Ubuntu 12.04, Ubuntu 14.04, Ubuntu 16.04, Fedora Linux 19, Fedora 20, Fedora 22, CentOS Linux 7, NetBSD 6, FreeBSD 10.3, OpenBSD 5.7, OpenBSD 6.0, OS X 10.10, OS X 10.11. There are currently no plans to port Kea to Windows platforms.
Required Software at Run-time Running Kea uses various extra software which may not be provided in the default installation of some operating systems, nor in the standard package collections. You may need to install this required software separately. (For the build requirements, also see .) Kea supports two cryptographic libraries: Botan and OpenSSL. Only one of them is required to be installed during compilation. If using Botan, Kea requires the Botan cryptographic library for C++ (), version 1.8, 1.9 or 1.10. If OpenSSL is used, (), then Kea requires the OpenSSL C++ library version 1.0.*. Support for later versions of Botan and OpenSSL will be added in future releases of Kea. Kea uses the log4cplus C++ logging library (). It requires log4cplus version 1.0.3 or later. In order to store lease information in a MySQL database, Kea requires MySQL headers and libraries. This is an optional dependency in that Kea can be built without MySQL support. In order to store lease information in a PostgreSQL database, Kea requires PostgreSQL headers and libraries. This is an optional dependency in that Kea can be built without PostgreSQL support. In order to store lease information in a Cassandra database (CQL), Kea requires Cassandra headers and libraries. This is an optional dependency in that Kea can be built without Cassandra support.
Kea Software Kea is modular. Part of this modularity is accomplished using multiple cooperating processes which, together, provide the server functionality. The following software is included with Kea: keactrl — Tool to start, stop, reconfigure, and report status for the Kea servers. kea-dhcp4 — The DHCPv4 server process. This process responds to DHCPv4 queries from clients. kea-dhcp6 — The DHCPv6 server process. This process responds to DHCPv6 queries from clients. kea-dhcp-ddns — The DHCP Dynamic DNS process. This process acts as an intermediary between the DHCP servers and DNS servers. It receives name update requests from the DHCP servers and sends DNS Update messages to the DNS servers. kea-admin — A useful tool for database backend maintenance (creating a new database, checking versions, upgrading etc.) kea-lfc — This process removes redundant information from the files used to provide persistent storage for the memfile data base backend. While it can be run standalone, it is normally run as and when required by the Kea DHCP servers. perfdhcp — A DHCP benchmarking tool which simulates multiple clients to test both DHCPv4 and DHCPv6 server performance.
The tools and modules are covered in full detail in this guide. In addition, manual pages are also provided in the default installation. Kea also provides C++ libraries and programmer interfaces for DHCP. These include detailed developer documentation and code examples.
kea-1.1.0/compatcheck/0000775000175000017500000000000012772742651011552 500000000000000kea-1.1.0/compatcheck/Makefile.in0000664000175000017500000003406312772742613013543 00000000000000# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = compatcheck DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am README ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4macros/ax_boost_for_kea.m4 \ $(top_srcdir)/m4macros/ax_isc_rpath.m4 \ $(top_srcdir)/m4macros/libtool.m4 \ $(top_srcdir)/m4macros/ltoptions.m4 \ $(top_srcdir)/m4macros/ltsugar.m4 \ $(top_srcdir)/m4macros/ltversion.m4 \ $(top_srcdir)/m4macros/lt~obsolete.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ASCIIDOC = @ASCIIDOC@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BOOST_INCLUDES = @BOOST_INCLUDES@ BOOST_LIBS = @BOOST_LIBS@ BOTAN_TOOL = @BOTAN_TOOL@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CQL_CPPFLAGS = @CQL_CPPFLAGS@ CQL_LIBS = @CQL_LIBS@ CRYPTO_CFLAGS = @CRYPTO_CFLAGS@ CRYPTO_INCLUDES = @CRYPTO_INCLUDES@ CRYPTO_LDFLAGS = @CRYPTO_LDFLAGS@ CRYPTO_LIBS = @CRYPTO_LIBS@ CRYPTO_PACKAGE = @CRYPTO_PACKAGE@ CRYPTO_RPATH = @CRYPTO_RPATH@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DBLATEX = @DBLATEX@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DISTCHECK_BOOST_CONFIGURE_FLAG = @DISTCHECK_BOOST_CONFIGURE_FLAG@ DISTCHECK_CRYPTO_CONFIGURE_FLAG = @DISTCHECK_CRYPTO_CONFIGURE_FLAG@ DISTCHECK_GTEST_CONFIGURE_FLAG = @DISTCHECK_GTEST_CONFIGURE_FLAG@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ ELINKS = @ELINKS@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GENHTML = @GENHTML@ GREP = @GREP@ GTEST_CONFIG = @GTEST_CONFIG@ GTEST_INCLUDES = @GTEST_INCLUDES@ GTEST_LDADD = @GTEST_LDADD@ GTEST_LDFLAGS = @GTEST_LDFLAGS@ GTEST_SOURCE = @GTEST_SOURCE@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ KEA_CXXFLAGS = @KEA_CXXFLAGS@ LCOV = @LCOV@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LEXLIB = @LEXLIB@ LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LOG4CPLUS_INCLUDES = @LOG4CPLUS_INCLUDES@ LOG4CPLUS_LIBS = @LOG4CPLUS_LIBS@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ MYSQL_LIBS = @MYSQL_LIBS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PERL = @PERL@ PGSQL_CPPFLAGS = @PGSQL_CPPFLAGS@ PGSQL_LIBS = @PGSQL_LIBS@ PKG_CONFIG = @PKG_CONFIG@ PLANTUML = @PLANTUML@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SEP = @SEP@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ USE_LCOV = @USE_LCOV@ VALGRIND = @VALGRIND@ VERSION = @VERSION@ WARNING_GCC_44_STRICT_ALIASING_CFLAG = @WARNING_GCC_44_STRICT_ALIASING_CFLAG@ XSLTPROC = @XSLTPROC@ YACC = @YACC@ YFLAGS = @YFLAGS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ all: all-am .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign compatcheck/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign compatcheck/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-data-local install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am \ install-data-local install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am tags-am uninstall \ uninstall-am # We're going to abuse install-data-local for a pre-install check. This may # not be the cleanest way to do this type of job, but that's the least ugly # one we've found. # # Note also that if any test needs to examine some file that has possibly # been installed before (e.g., older DB or configuration file), it should be # referenced with the prefix of DESTDIR. Otherwise # 'make DESTDIR=/somewhere install' may not work. install-data-local: if test -e $(DESTDIR)$(localstatedir)/$(PACKAGE)/zone.sqlite3; then \ $(SHELL) $(top_builddir)/src/bin/dbutil/run_dbutil.sh --check \ $(DESTDIR)$(localstatedir)/$(PACKAGE)/zone.sqlite3 || \ (echo "\nSQLite3 DB file schema version is old. " \ "Please run: " \ "$(abs_top_builddir)/src/bin/dbutil/run_dbutil.sh --upgrade " \ "$(DESTDIR)$(localstatedir)/$(PACKAGE)/zone.sqlite3"; exit 1) \ fi # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: kea-1.1.0/compatcheck/Makefile.am0000664000175000017500000000152412772017075013523 00000000000000# We're going to abuse install-data-local for a pre-install check. This may # not be the cleanest way to do this type of job, but that's the least ugly # one we've found. # # Note also that if any test needs to examine some file that has possibly # been installed before (e.g., older DB or configuration file), it should be # referenced with the prefix of DESTDIR. Otherwise # 'make DESTDIR=/somewhere install' may not work. install-data-local: if test -e $(DESTDIR)$(localstatedir)/$(PACKAGE)/zone.sqlite3; then \ $(SHELL) $(top_builddir)/src/bin/dbutil/run_dbutil.sh --check \ $(DESTDIR)$(localstatedir)/$(PACKAGE)/zone.sqlite3 || \ (echo "\nSQLite3 DB file schema version is old. " \ "Please run: " \ "$(abs_top_builddir)/src/bin/dbutil/run_dbutil.sh --upgrade " \ "$(DESTDIR)$(localstatedir)/$(PACKAGE)/zone.sqlite3"; exit 1) \ fi kea-1.1.0/compatcheck/README0000664000175000017500000000050212772017075012342 00000000000000This directory is a collection of compatibility checker programs. They will be run before any other installation attempts on 'make install' to see if the installation causes any substantial compatibility problems with existing configuratons. If any checker program finds an issue, 'make install' will stop at that point. kea-1.1.0/ext/0000775000175000017500000000000012772742656010076 500000000000000kea-1.1.0/ext/Makefile.in0000664000175000017500000004673112772742613012067 00000000000000# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ @HAVE_GTEST_SOURCE_TRUE@am__append_1 = gtest subdir = ext DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4macros/ax_boost_for_kea.m4 \ $(top_srcdir)/m4macros/ax_isc_rpath.m4 \ $(top_srcdir)/m4macros/libtool.m4 \ $(top_srcdir)/m4macros/ltoptions.m4 \ $(top_srcdir)/m4macros/ltsugar.m4 \ $(top_srcdir)/m4macros/ltversion.m4 \ $(top_srcdir)/m4macros/lt~obsolete.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ install-exec-recursive install-html-recursive \ install-info-recursive install-pdf-recursive \ install-ps-recursive install-recursive installcheck-recursive \ installdirs-recursive pdf-recursive ps-recursive \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ distdir am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DIST_SUBDIRS = coroutine gtest DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ASCIIDOC = @ASCIIDOC@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BOOST_INCLUDES = @BOOST_INCLUDES@ BOOST_LIBS = @BOOST_LIBS@ BOTAN_TOOL = @BOTAN_TOOL@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CQL_CPPFLAGS = @CQL_CPPFLAGS@ CQL_LIBS = @CQL_LIBS@ CRYPTO_CFLAGS = @CRYPTO_CFLAGS@ CRYPTO_INCLUDES = @CRYPTO_INCLUDES@ CRYPTO_LDFLAGS = @CRYPTO_LDFLAGS@ CRYPTO_LIBS = @CRYPTO_LIBS@ CRYPTO_PACKAGE = @CRYPTO_PACKAGE@ CRYPTO_RPATH = @CRYPTO_RPATH@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DBLATEX = @DBLATEX@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DISTCHECK_BOOST_CONFIGURE_FLAG = @DISTCHECK_BOOST_CONFIGURE_FLAG@ DISTCHECK_CRYPTO_CONFIGURE_FLAG = @DISTCHECK_CRYPTO_CONFIGURE_FLAG@ DISTCHECK_GTEST_CONFIGURE_FLAG = @DISTCHECK_GTEST_CONFIGURE_FLAG@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ ELINKS = @ELINKS@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GENHTML = @GENHTML@ GREP = @GREP@ GTEST_CONFIG = @GTEST_CONFIG@ GTEST_INCLUDES = @GTEST_INCLUDES@ GTEST_LDADD = @GTEST_LDADD@ GTEST_LDFLAGS = @GTEST_LDFLAGS@ GTEST_SOURCE = @GTEST_SOURCE@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ KEA_CXXFLAGS = @KEA_CXXFLAGS@ LCOV = @LCOV@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LEXLIB = @LEXLIB@ LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LOG4CPLUS_INCLUDES = @LOG4CPLUS_INCLUDES@ LOG4CPLUS_LIBS = @LOG4CPLUS_LIBS@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ MYSQL_LIBS = @MYSQL_LIBS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PERL = @PERL@ PGSQL_CPPFLAGS = @PGSQL_CPPFLAGS@ PGSQL_LIBS = @PGSQL_LIBS@ PKG_CONFIG = @PKG_CONFIG@ PLANTUML = @PLANTUML@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SEP = @SEP@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ USE_LCOV = @USE_LCOV@ VALGRIND = @VALGRIND@ VERSION = @VERSION@ WARNING_GCC_44_STRICT_ALIASING_CFLAG = @WARNING_GCC_44_STRICT_ALIASING_CFLAG@ XSLTPROC = @XSLTPROC@ YACC = @YACC@ YFLAGS = @YFLAGS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ SUBDIRS = coroutine $(am__append_1) all: all-recursive .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign ext/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign ext/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs # This directory's subdirectories are mostly independent; you can cd # into them and run 'make' without going through this Makefile. # To change the values of 'make' variables: instead of editing Makefiles, # (1) if the variable is set in 'config.status', edit 'config.status' # (which will cause the Makefiles to be regenerated when you run 'make'); # (2) otherwise, pass the desired values on the 'make' command line. $(am__recursive_targets): @fail=; \ if $(am__make_keepgoing); then \ failcom='fail=yes'; \ else \ failcom='exit 1'; \ fi; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-recursive CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-recursive cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done check-am: all-am check: check-recursive all-am: Makefile installdirs: installdirs-recursive installdirs-am: install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-recursive clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-recursive -rm -f Makefile distclean-am: clean-am distclean-generic distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: .MAKE: $(am__recursive_targets) install-am install-strip .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ check-am clean clean-generic clean-libtool cscopelist-am ctags \ ctags-am distclean distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ installdirs-am maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ ps ps-am tags tags-am uninstall uninstall-am # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: kea-1.1.0/ext/gtest/0000775000175000017500000000000012772742656011224 500000000000000kea-1.1.0/ext/gtest/Makefile.in0000664000175000017500000006173212772742614013214 00000000000000# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = ext/gtest DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/depcomp ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4macros/ax_boost_for_kea.m4 \ $(top_srcdir)/m4macros/ax_isc_rpath.m4 \ $(top_srcdir)/m4macros/libtool.m4 \ $(top_srcdir)/m4macros/ltoptions.m4 \ $(top_srcdir)/m4macros/ltsugar.m4 \ $(top_srcdir)/m4macros/ltversion.m4 \ $(top_srcdir)/m4macros/lt~obsolete.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = LIBRARIES = $(noinst_LIBRARIES) ARFLAGS = cru AM_V_AR = $(am__v_AR_@AM_V@) am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@) am__v_AR_0 = @echo " AR " $@; am__v_AR_1 = libgtest_a_AR = $(AR) $(ARFLAGS) libgtest_a_LIBADD = nodist_libgtest_a_OBJECTS = libgtest_a-gtest-all.$(OBJEXT) libgtest_a_OBJECTS = $(nodist_libgtest_a_OBJECTS) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CXXFLAGS) $(CXXFLAGS) AM_V_CXX = $(am__v_CXX_@AM_V@) am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@) am__v_CXX_0 = @echo " CXX " $@; am__v_CXX_1 = CXXLD = $(CXX) CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CXXLD = $(am__v_CXXLD_@AM_V@) am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@) am__v_CXXLD_0 = @echo " CXXLD " $@; am__v_CXXLD_1 = SOURCES = $(nodist_libgtest_a_SOURCES) DIST_SOURCES = RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ install-exec-recursive install-html-recursive \ install-info-recursive install-pdf-recursive \ install-ps-recursive install-recursive installcheck-recursive \ installdirs-recursive pdf-recursive ps-recursive \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ distdir am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DIST_SUBDIRS = $(SUBDIRS) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ASCIIDOC = @ASCIIDOC@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BOOST_INCLUDES = @BOOST_INCLUDES@ BOOST_LIBS = @BOOST_LIBS@ BOTAN_TOOL = @BOTAN_TOOL@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CQL_CPPFLAGS = @CQL_CPPFLAGS@ CQL_LIBS = @CQL_LIBS@ CRYPTO_CFLAGS = @CRYPTO_CFLAGS@ CRYPTO_INCLUDES = @CRYPTO_INCLUDES@ CRYPTO_LDFLAGS = @CRYPTO_LDFLAGS@ CRYPTO_LIBS = @CRYPTO_LIBS@ CRYPTO_PACKAGE = @CRYPTO_PACKAGE@ CRYPTO_RPATH = @CRYPTO_RPATH@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DBLATEX = @DBLATEX@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DISTCHECK_BOOST_CONFIGURE_FLAG = @DISTCHECK_BOOST_CONFIGURE_FLAG@ DISTCHECK_CRYPTO_CONFIGURE_FLAG = @DISTCHECK_CRYPTO_CONFIGURE_FLAG@ DISTCHECK_GTEST_CONFIGURE_FLAG = @DISTCHECK_GTEST_CONFIGURE_FLAG@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ ELINKS = @ELINKS@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GENHTML = @GENHTML@ GREP = @GREP@ GTEST_CONFIG = @GTEST_CONFIG@ GTEST_INCLUDES = @GTEST_INCLUDES@ GTEST_LDADD = @GTEST_LDADD@ GTEST_LDFLAGS = @GTEST_LDFLAGS@ GTEST_SOURCE = @GTEST_SOURCE@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ KEA_CXXFLAGS = @KEA_CXXFLAGS@ LCOV = @LCOV@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LEXLIB = @LEXLIB@ LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LOG4CPLUS_INCLUDES = @LOG4CPLUS_INCLUDES@ LOG4CPLUS_LIBS = @LOG4CPLUS_LIBS@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ MYSQL_LIBS = @MYSQL_LIBS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PERL = @PERL@ PGSQL_CPPFLAGS = @PGSQL_CPPFLAGS@ PGSQL_LIBS = @PGSQL_LIBS@ PKG_CONFIG = @PKG_CONFIG@ PLANTUML = @PLANTUML@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SEP = @SEP@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ USE_LCOV = @USE_LCOV@ VALGRIND = @VALGRIND@ VERSION = @VERSION@ WARNING_GCC_44_STRICT_ALIASING_CFLAG = @WARNING_GCC_44_STRICT_ALIASING_CFLAG@ XSLTPROC = @XSLTPROC@ YACC = @YACC@ YFLAGS = @YFLAGS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ SUBDIRS = . CLEANFILES = gtest-all.cc noinst_LIBRARIES = libgtest.a libgtest_a_CXXFLAGS = $(GTEST_INCLUDES) $(AM_CXXFLAGS) nodist_libgtest_a_SOURCES = gtest-all.cc all: all-recursive .SUFFIXES: .SUFFIXES: .cc .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign ext/gtest/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign ext/gtest/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-noinstLIBRARIES: -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) libgtest.a: $(libgtest_a_OBJECTS) $(libgtest_a_DEPENDENCIES) $(EXTRA_libgtest_a_DEPENDENCIES) $(AM_V_at)-rm -f libgtest.a $(AM_V_AR)$(libgtest_a_AR) libgtest.a $(libgtest_a_OBJECTS) $(libgtest_a_LIBADD) $(AM_V_at)$(RANLIB) libgtest.a mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgtest_a-gtest-all.Po@am__quote@ .cc.o: @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $< .cc.obj: @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .cc.lo: @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $< libgtest_a-gtest-all.o: gtest-all.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgtest_a_CXXFLAGS) $(CXXFLAGS) -MT libgtest_a-gtest-all.o -MD -MP -MF $(DEPDIR)/libgtest_a-gtest-all.Tpo -c -o libgtest_a-gtest-all.o `test -f 'gtest-all.cc' || echo '$(srcdir)/'`gtest-all.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgtest_a-gtest-all.Tpo $(DEPDIR)/libgtest_a-gtest-all.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='gtest-all.cc' object='libgtest_a-gtest-all.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgtest_a_CXXFLAGS) $(CXXFLAGS) -c -o libgtest_a-gtest-all.o `test -f 'gtest-all.cc' || echo '$(srcdir)/'`gtest-all.cc libgtest_a-gtest-all.obj: gtest-all.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgtest_a_CXXFLAGS) $(CXXFLAGS) -MT libgtest_a-gtest-all.obj -MD -MP -MF $(DEPDIR)/libgtest_a-gtest-all.Tpo -c -o libgtest_a-gtest-all.obj `if test -f 'gtest-all.cc'; then $(CYGPATH_W) 'gtest-all.cc'; else $(CYGPATH_W) '$(srcdir)/gtest-all.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgtest_a-gtest-all.Tpo $(DEPDIR)/libgtest_a-gtest-all.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='gtest-all.cc' object='libgtest_a-gtest-all.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgtest_a_CXXFLAGS) $(CXXFLAGS) -c -o libgtest_a-gtest-all.obj `if test -f 'gtest-all.cc'; then $(CYGPATH_W) 'gtest-all.cc'; else $(CYGPATH_W) '$(srcdir)/gtest-all.cc'; fi` mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs # This directory's subdirectories are mostly independent; you can cd # into them and run 'make' without going through this Makefile. # To change the values of 'make' variables: instead of editing Makefiles, # (1) if the variable is set in 'config.status', edit 'config.status' # (which will cause the Makefiles to be regenerated when you run 'make'); # (2) otherwise, pass the desired values on the 'make' command line. $(am__recursive_targets): @fail=; \ if $(am__make_keepgoing); then \ failcom='fail=yes'; \ else \ failcom='exit 1'; \ fi; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-recursive CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-recursive cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done check-am: all-am check: check-recursive all-am: Makefile $(LIBRARIES) installdirs: installdirs-recursive installdirs-am: install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-recursive clean-am: clean-generic clean-libtool clean-noinstLIBRARIES \ mostlyclean-am distclean: distclean-recursive -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: .MAKE: $(am__recursive_targets) install-am install-strip .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ check-am clean clean-generic clean-libtool \ clean-noinstLIBRARIES cscopelist-am ctags ctags-am distclean \ distclean-compile distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ installdirs-am maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am gtest-all.cc: $(GTEST_SOURCE)/src/gtest-all.cc cp -p $(GTEST_SOURCE)/src/gtest-all.cc $@ # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: kea-1.1.0/ext/gtest/Makefile.am0000664000175000017500000000040112772017075013161 00000000000000SUBDIRS = . CLEANFILES = gtest-all.cc noinst_LIBRARIES = libgtest.a libgtest_a_CXXFLAGS = $(GTEST_INCLUDES) $(AM_CXXFLAGS) nodist_libgtest_a_SOURCES = gtest-all.cc gtest-all.cc: $(GTEST_SOURCE)/src/gtest-all.cc cp -p $(GTEST_SOURCE)/src/gtest-all.cc $@ kea-1.1.0/ext/Makefile.am0000664000175000017500000000010112772017075012030 00000000000000SUBDIRS = coroutine if HAVE_GTEST_SOURCE SUBDIRS += gtest endif kea-1.1.0/ext/coroutine/0000775000175000017500000000000012772742656012105 500000000000000kea-1.1.0/ext/coroutine/Makefile.in0000664000175000017500000003232112772742613014064 00000000000000# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = ext/coroutine DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4macros/ax_boost_for_kea.m4 \ $(top_srcdir)/m4macros/ax_isc_rpath.m4 \ $(top_srcdir)/m4macros/libtool.m4 \ $(top_srcdir)/m4macros/ltoptions.m4 \ $(top_srcdir)/m4macros/ltsugar.m4 \ $(top_srcdir)/m4macros/ltversion.m4 \ $(top_srcdir)/m4macros/lt~obsolete.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ASCIIDOC = @ASCIIDOC@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BOOST_INCLUDES = @BOOST_INCLUDES@ BOOST_LIBS = @BOOST_LIBS@ BOTAN_TOOL = @BOTAN_TOOL@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CQL_CPPFLAGS = @CQL_CPPFLAGS@ CQL_LIBS = @CQL_LIBS@ CRYPTO_CFLAGS = @CRYPTO_CFLAGS@ CRYPTO_INCLUDES = @CRYPTO_INCLUDES@ CRYPTO_LDFLAGS = @CRYPTO_LDFLAGS@ CRYPTO_LIBS = @CRYPTO_LIBS@ CRYPTO_PACKAGE = @CRYPTO_PACKAGE@ CRYPTO_RPATH = @CRYPTO_RPATH@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DBLATEX = @DBLATEX@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DISTCHECK_BOOST_CONFIGURE_FLAG = @DISTCHECK_BOOST_CONFIGURE_FLAG@ DISTCHECK_CRYPTO_CONFIGURE_FLAG = @DISTCHECK_CRYPTO_CONFIGURE_FLAG@ DISTCHECK_GTEST_CONFIGURE_FLAG = @DISTCHECK_GTEST_CONFIGURE_FLAG@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ ELINKS = @ELINKS@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GENHTML = @GENHTML@ GREP = @GREP@ GTEST_CONFIG = @GTEST_CONFIG@ GTEST_INCLUDES = @GTEST_INCLUDES@ GTEST_LDADD = @GTEST_LDADD@ GTEST_LDFLAGS = @GTEST_LDFLAGS@ GTEST_SOURCE = @GTEST_SOURCE@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ KEA_CXXFLAGS = @KEA_CXXFLAGS@ LCOV = @LCOV@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LEXLIB = @LEXLIB@ LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LOG4CPLUS_INCLUDES = @LOG4CPLUS_INCLUDES@ LOG4CPLUS_LIBS = @LOG4CPLUS_LIBS@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ MYSQL_LIBS = @MYSQL_LIBS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PERL = @PERL@ PGSQL_CPPFLAGS = @PGSQL_CPPFLAGS@ PGSQL_LIBS = @PGSQL_LIBS@ PKG_CONFIG = @PKG_CONFIG@ PLANTUML = @PLANTUML@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SEP = @SEP@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ USE_LCOV = @USE_LCOV@ VALGRIND = @VALGRIND@ VERSION = @VERSION@ WARNING_GCC_44_STRICT_ALIASING_CFLAG = @WARNING_GCC_44_STRICT_ALIASING_CFLAG@ XSLTPROC = @XSLTPROC@ YACC = @YACC@ YFLAGS = @YFLAGS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ EXTRA_DIST = LICENSE_1_0.txt all: all-am .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign ext/coroutine/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign ext/coroutine/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags-am uninstall uninstall-am # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: kea-1.1.0/ext/coroutine/LICENSE_1_0.txt0000664000175000017500000000247212772017075014302 00000000000000Boost Software License - Version 1.0 - August 17th, 2003 Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the software and accompanying documentation covered by this license (the "Software") to use, reproduce, display, distribute, execute, and transmit the Software, and to prepare derivative works of the Software, and to permit third-parties to whom the Software is furnished to do so, all subject to the following: The copyright notices in the Software and this entire statement, including the above license grant, this restriction and the following disclaimer, must be included in all copies of the Software, in whole or in part, and all derivative works of the Software, unless such copies or derivative works are solely in the form of machine-executable object code generated by a source language processor. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. kea-1.1.0/ext/coroutine/Makefile.am0000664000175000017500000000003512772017075014045 00000000000000EXTRA_DIST = LICENSE_1_0.txt kea-1.1.0/ext/coroutine/coroutine.h0000664000175000017500000001143512772017075014177 00000000000000// // coroutine.h // ~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef COROUTINE_HPP #define COROUTINE_HPP // \brief Coroutine object // // A coroutine object maintains the state of a re-enterable routine. It // is assignable and copy-constructable, and can be used as a base class // for a class that uses it, or as a data member. The copy overhead is // a single int. // // A reenterable function contains a CORO_REENTER (coroutine) { ... } // block. Whenever an asychrnonous operation is initiated within the // routine, the function is provided as the handler object. (The simplest // way to do this is to have the reenterable function be the operator() // member for the coroutine object itself.) For example: // // CORO_YIELD socket->async_read_some(buffer, *this); // // The CORO_YIELD keyword updates the current status of the coroutine to // indicate the line number currently being executed. The // async_read_some() call is initiated, with a copy of the updated // corotutine as its handler object, and the current coroutine exits. When // the async_read_some() call finishes, the copied coroutine will be // called, and will resume processing exactly where the original one left // off--right after asynchronous call. This allows asynchronous I/O // routines to be written with a logical flow, step following step, rather // than as a linked chain of separate handler functions. // // When necessary, a coroutine can fork itself using the CORO_FORK keyword. // This updates the status of the coroutine and makes a copy. The copy can // then be called directly or posted to the ASIO service queue so that both // coroutines will continue forward, one "parent" and one "child". The // is_parent() and is_child() methods indicate which is which. // // The CORO_REENTER, CORO_YIELD and CORO_FORK keywords are implemented // via preprocessor macros. The CORO_REENTER block is actually a large, // complex switch statement. Because of this, inline variable declaration // is impossible within CORO_REENTER unless it is done in a subsidiary // scope--and if it is, that scope cannot contain CORO_YIELD or CORO_FORK // keywords. // // Because coroutines are frequently copied, it is best to minimize copy // overhead by limiting the size of data members in derived classes. // // It should be noted that when a coroutine falls out of scope its memory // is reclaimed, even though it may be scheduled to resume when an // asynchronous operation completes. Any shared_ptr<> objects declared in // the coroutine may be destroyed if their reference count drops to zero, // in which case the coroutine will have serious problems once it resumes. // One solution so this is to have the space that will be used by a // coroutine pre-allocated and stored on a free list; a new coroutine can // fetch the block of space off a free list, place a shared pointer to it // on an "in use" list, and carry on. The reference in the "in use" list // would prevent the data from being destroyed. class coroutine { public: coroutine() : value_(0) {} virtual ~coroutine() {} bool is_child() const { return value_ < 0; } bool is_parent() const { return !is_child(); } bool is_complete() const { return value_ == -1; } int get_value() const { return value_; } private: friend class coroutine_ref; int value_; }; class coroutine_ref { public: coroutine_ref(coroutine& c) : value_(c.value_), modified_(false) {} coroutine_ref(coroutine* c) : value_(c->value_), modified_(false) {} ~coroutine_ref() { if (!modified_) value_ = -1; } operator int() const { return value_; } int& operator=(int v) { modified_ = true; return value_ = v; } private: void operator=(const coroutine_ref&); int& value_; bool modified_; }; #define CORO_REENTER(c) \ switch (coroutine_ref _coro_value = c) \ case -1: if (_coro_value) \ { \ goto terminate_coroutine; \ terminate_coroutine: \ _coro_value = -1; \ goto bail_out_of_coroutine; \ bail_out_of_coroutine: \ break; \ } \ else case 0: #define CORO_YIELD \ for (_coro_value = __LINE__;;) \ if (_coro_value == 0) \ { \ case __LINE__: ; \ break; \ } \ else \ switch (_coro_value ? 0 : 1) \ for (;;) \ case -1: if (_coro_value) \ goto terminate_coroutine; \ else for (;;) \ case 1: if (_coro_value) \ goto bail_out_of_coroutine; \ else case 0: #define CORO_FORK \ for (_coro_value = -__LINE__;; _coro_value = __LINE__) \ if (_coro_value == __LINE__) \ { \ case -__LINE__: ; \ break; \ } \ else #endif // COROUTINE_HPP kea-1.1.0/src/0000775000175000017500000000000012772742667010067 500000000000000kea-1.1.0/src/Makefile.in0000664000175000017500000004703312772742614012053 00000000000000# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = src DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4macros/ax_boost_for_kea.m4 \ $(top_srcdir)/m4macros/ax_isc_rpath.m4 \ $(top_srcdir)/m4macros/libtool.m4 \ $(top_srcdir)/m4macros/ltoptions.m4 \ $(top_srcdir)/m4macros/ltsugar.m4 \ $(top_srcdir)/m4macros/ltversion.m4 \ $(top_srcdir)/m4macros/lt~obsolete.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ install-exec-recursive install-html-recursive \ install-info-recursive install-pdf-recursive \ install-ps-recursive install-recursive installcheck-recursive \ installdirs-recursive pdf-recursive ps-recursive \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ distdir am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DIST_SUBDIRS = $(SUBDIRS) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ASCIIDOC = @ASCIIDOC@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BOOST_INCLUDES = @BOOST_INCLUDES@ BOOST_LIBS = @BOOST_LIBS@ BOTAN_TOOL = @BOTAN_TOOL@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CQL_CPPFLAGS = @CQL_CPPFLAGS@ CQL_LIBS = @CQL_LIBS@ CRYPTO_CFLAGS = @CRYPTO_CFLAGS@ CRYPTO_INCLUDES = @CRYPTO_INCLUDES@ CRYPTO_LDFLAGS = @CRYPTO_LDFLAGS@ CRYPTO_LIBS = @CRYPTO_LIBS@ CRYPTO_PACKAGE = @CRYPTO_PACKAGE@ CRYPTO_RPATH = @CRYPTO_RPATH@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DBLATEX = @DBLATEX@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DISTCHECK_BOOST_CONFIGURE_FLAG = @DISTCHECK_BOOST_CONFIGURE_FLAG@ DISTCHECK_CRYPTO_CONFIGURE_FLAG = @DISTCHECK_CRYPTO_CONFIGURE_FLAG@ DISTCHECK_GTEST_CONFIGURE_FLAG = @DISTCHECK_GTEST_CONFIGURE_FLAG@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ ELINKS = @ELINKS@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GENHTML = @GENHTML@ GREP = @GREP@ GTEST_CONFIG = @GTEST_CONFIG@ GTEST_INCLUDES = @GTEST_INCLUDES@ GTEST_LDADD = @GTEST_LDADD@ GTEST_LDFLAGS = @GTEST_LDFLAGS@ GTEST_SOURCE = @GTEST_SOURCE@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ KEA_CXXFLAGS = @KEA_CXXFLAGS@ LCOV = @LCOV@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LEXLIB = @LEXLIB@ LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LOG4CPLUS_INCLUDES = @LOG4CPLUS_INCLUDES@ LOG4CPLUS_LIBS = @LOG4CPLUS_LIBS@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ MYSQL_LIBS = @MYSQL_LIBS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PERL = @PERL@ PGSQL_CPPFLAGS = @PGSQL_CPPFLAGS@ PGSQL_LIBS = @PGSQL_LIBS@ PKG_CONFIG = @PKG_CONFIG@ PLANTUML = @PLANTUML@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SEP = @SEP@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ USE_LCOV = @USE_LCOV@ VALGRIND = @VALGRIND@ VERSION = @VERSION@ WARNING_GCC_44_STRICT_ALIASING_CFLAG = @WARNING_GCC_44_STRICT_ALIASING_CFLAG@ XSLTPROC = @XSLTPROC@ YACC = @YACC@ YFLAGS = @YFLAGS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ SUBDIRS = share lib bin hooks EXTRA_DIST = \ cppcheck-suppress.lst \ valgrind-suppressions \ valgrind-suppressions.revisit \ defaults.h all: all-recursive .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign src/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs # This directory's subdirectories are mostly independent; you can cd # into them and run 'make' without going through this Makefile. # To change the values of 'make' variables: instead of editing Makefiles, # (1) if the variable is set in 'config.status', edit 'config.status' # (which will cause the Makefiles to be regenerated when you run 'make'); # (2) otherwise, pass the desired values on the 'make' command line. $(am__recursive_targets): @fail=; \ if $(am__make_keepgoing); then \ failcom='fail=yes'; \ else \ failcom='exit 1'; \ fi; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-recursive CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-recursive cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done check-am: all-am check: check-recursive all-am: Makefile installdirs: installdirs-recursive installdirs-am: install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-recursive clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-recursive -rm -f Makefile distclean-am: clean-am distclean-generic distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: .MAKE: $(am__recursive_targets) install-am install-strip .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ check-am clean clean-generic clean-libtool cscopelist-am ctags \ ctags-am distclean distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ installdirs-am maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ ps ps-am tags tags-am uninstall uninstall-am # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: kea-1.1.0/src/lib/0000775000175000017500000000000012772742663010631 500000000000000kea-1.1.0/src/lib/Makefile.in0000664000175000017500000004711312772742615012621 00000000000000# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = src/lib DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4macros/ax_boost_for_kea.m4 \ $(top_srcdir)/m4macros/ax_isc_rpath.m4 \ $(top_srcdir)/m4macros/libtool.m4 \ $(top_srcdir)/m4macros/ltoptions.m4 \ $(top_srcdir)/m4macros/ltsugar.m4 \ $(top_srcdir)/m4macros/ltversion.m4 \ $(top_srcdir)/m4macros/lt~obsolete.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ install-exec-recursive install-html-recursive \ install-info-recursive install-pdf-recursive \ install-ps-recursive install-recursive installcheck-recursive \ installdirs-recursive pdf-recursive ps-recursive \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ distdir am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DIST_SUBDIRS = $(SUBDIRS) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ASCIIDOC = @ASCIIDOC@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BOOST_INCLUDES = @BOOST_INCLUDES@ BOOST_LIBS = @BOOST_LIBS@ BOTAN_TOOL = @BOTAN_TOOL@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CQL_CPPFLAGS = @CQL_CPPFLAGS@ CQL_LIBS = @CQL_LIBS@ CRYPTO_CFLAGS = @CRYPTO_CFLAGS@ CRYPTO_INCLUDES = @CRYPTO_INCLUDES@ CRYPTO_LDFLAGS = @CRYPTO_LDFLAGS@ CRYPTO_LIBS = @CRYPTO_LIBS@ CRYPTO_PACKAGE = @CRYPTO_PACKAGE@ CRYPTO_RPATH = @CRYPTO_RPATH@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DBLATEX = @DBLATEX@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DISTCHECK_BOOST_CONFIGURE_FLAG = @DISTCHECK_BOOST_CONFIGURE_FLAG@ DISTCHECK_CRYPTO_CONFIGURE_FLAG = @DISTCHECK_CRYPTO_CONFIGURE_FLAG@ DISTCHECK_GTEST_CONFIGURE_FLAG = @DISTCHECK_GTEST_CONFIGURE_FLAG@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ ELINKS = @ELINKS@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GENHTML = @GENHTML@ GREP = @GREP@ GTEST_CONFIG = @GTEST_CONFIG@ GTEST_INCLUDES = @GTEST_INCLUDES@ GTEST_LDADD = @GTEST_LDADD@ GTEST_LDFLAGS = @GTEST_LDFLAGS@ GTEST_SOURCE = @GTEST_SOURCE@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ KEA_CXXFLAGS = @KEA_CXXFLAGS@ LCOV = @LCOV@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LEXLIB = @LEXLIB@ LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LOG4CPLUS_INCLUDES = @LOG4CPLUS_INCLUDES@ LOG4CPLUS_LIBS = @LOG4CPLUS_LIBS@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ MYSQL_LIBS = @MYSQL_LIBS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PERL = @PERL@ PGSQL_CPPFLAGS = @PGSQL_CPPFLAGS@ PGSQL_LIBS = @PGSQL_LIBS@ PKG_CONFIG = @PKG_CONFIG@ PLANTUML = @PLANTUML@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SEP = @SEP@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ USE_LCOV = @USE_LCOV@ VALGRIND = @VALGRIND@ VERSION = @VERSION@ WARNING_GCC_44_STRICT_ALIASING_CFLAG = @WARNING_GCC_44_STRICT_ALIASING_CFLAG@ XSLTPROC = @XSLTPROC@ YACC = @YACC@ YFLAGS = @YFLAGS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ # The following build order must be maintained. SUBDIRS = exceptions util log cryptolink dns cc hooks asiolink testutils dhcp config \ stats asiodns dhcp_ddns eval dhcpsrv cfgrpt all: all-recursive .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/lib/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign src/lib/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs # This directory's subdirectories are mostly independent; you can cd # into them and run 'make' without going through this Makefile. # To change the values of 'make' variables: instead of editing Makefiles, # (1) if the variable is set in 'config.status', edit 'config.status' # (which will cause the Makefiles to be regenerated when you run 'make'); # (2) otherwise, pass the desired values on the 'make' command line. $(am__recursive_targets): @fail=; \ if $(am__make_keepgoing); then \ failcom='fail=yes'; \ else \ failcom='exit 1'; \ fi; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-recursive CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-recursive cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done check-am: all-am check: check-recursive all-am: Makefile installdirs: installdirs-recursive installdirs-am: install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-recursive clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-recursive -rm -f Makefile distclean-am: clean-am distclean-generic distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: .MAKE: $(am__recursive_targets) install-am install-strip .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ check-am clean clean-generic clean-libtool cscopelist-am ctags \ ctags-am distclean distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ installdirs-am maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ ps ps-am tags tags-am uninstall uninstall-am # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: kea-1.1.0/src/lib/config/0000775000175000017500000000000012772742662012075 500000000000000kea-1.1.0/src/lib/config/Makefile.in0000664000175000017500000007223112772742615014065 00000000000000# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = src/lib/config DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/depcomp ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4macros/ax_boost_for_kea.m4 \ $(top_srcdir)/m4macros/ax_isc_rpath.m4 \ $(top_srcdir)/m4macros/libtool.m4 \ $(top_srcdir)/m4macros/ltoptions.m4 \ $(top_srcdir)/m4macros/ltsugar.m4 \ $(top_srcdir)/m4macros/ltversion.m4 \ $(top_srcdir)/m4macros/lt~obsolete.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(libdir)" LTLIBRARIES = $(lib_LTLIBRARIES) am__DEPENDENCIES_1 = libkea_cfgclient_la_DEPENDENCIES = \ $(top_builddir)/src/lib/dhcp/libkea-dhcp++.la \ $(top_builddir)/src/lib/asiolink/libkea-asiolink.la \ $(top_builddir)/src/lib/cc/libkea-cc.la \ $(top_builddir)/src/lib/dns/libkea-dns++.la \ $(top_builddir)/src/lib/cryptolink/libkea-cryptolink.la \ $(top_builddir)/src/lib/log/libkea-log.la \ $(top_builddir)/src/lib/util/threads/libkea-threads.la \ $(top_builddir)/src/lib/util/libkea-util.la \ $(top_builddir)/src/lib/exceptions/libkea-exceptions.la \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) am_libkea_cfgclient_la_OBJECTS = config_data.lo module_spec.lo \ command_mgr.lo command_socket.lo command_socket_factory.lo \ config_log.lo nodist_libkea_cfgclient_la_OBJECTS = config_messages.lo libkea_cfgclient_la_OBJECTS = $(am_libkea_cfgclient_la_OBJECTS) \ $(nodist_libkea_cfgclient_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = libkea_cfgclient_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(AM_CXXFLAGS) $(CXXFLAGS) $(libkea_cfgclient_la_LDFLAGS) \ $(LDFLAGS) -o $@ AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CXXFLAGS) $(CXXFLAGS) AM_V_CXX = $(am__v_CXX_@AM_V@) am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@) am__v_CXX_0 = @echo " CXX " $@; am__v_CXX_1 = CXXLD = $(CXX) CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CXXLD = $(am__v_CXXLD_@AM_V@) am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@) am__v_CXXLD_0 = @echo " CXXLD " $@; am__v_CXXLD_1 = COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libkea_cfgclient_la_SOURCES) \ $(nodist_libkea_cfgclient_la_SOURCES) DIST_SOURCES = $(libkea_cfgclient_la_SOURCES) RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ install-exec-recursive install-html-recursive \ install-info-recursive install-pdf-recursive \ install-ps-recursive install-recursive installcheck-recursive \ installdirs-recursive pdf-recursive ps-recursive \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ distdir am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DIST_SUBDIRS = $(SUBDIRS) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ASCIIDOC = @ASCIIDOC@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BOOST_INCLUDES = @BOOST_INCLUDES@ BOOST_LIBS = @BOOST_LIBS@ BOTAN_TOOL = @BOTAN_TOOL@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CQL_CPPFLAGS = @CQL_CPPFLAGS@ CQL_LIBS = @CQL_LIBS@ CRYPTO_CFLAGS = @CRYPTO_CFLAGS@ CRYPTO_INCLUDES = @CRYPTO_INCLUDES@ CRYPTO_LDFLAGS = @CRYPTO_LDFLAGS@ CRYPTO_LIBS = @CRYPTO_LIBS@ CRYPTO_PACKAGE = @CRYPTO_PACKAGE@ CRYPTO_RPATH = @CRYPTO_RPATH@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DBLATEX = @DBLATEX@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DISTCHECK_BOOST_CONFIGURE_FLAG = @DISTCHECK_BOOST_CONFIGURE_FLAG@ DISTCHECK_CRYPTO_CONFIGURE_FLAG = @DISTCHECK_CRYPTO_CONFIGURE_FLAG@ DISTCHECK_GTEST_CONFIGURE_FLAG = @DISTCHECK_GTEST_CONFIGURE_FLAG@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ ELINKS = @ELINKS@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GENHTML = @GENHTML@ GREP = @GREP@ GTEST_CONFIG = @GTEST_CONFIG@ GTEST_INCLUDES = @GTEST_INCLUDES@ GTEST_LDADD = @GTEST_LDADD@ GTEST_LDFLAGS = @GTEST_LDFLAGS@ GTEST_SOURCE = @GTEST_SOURCE@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ KEA_CXXFLAGS = @KEA_CXXFLAGS@ LCOV = @LCOV@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LEXLIB = @LEXLIB@ LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LOG4CPLUS_INCLUDES = @LOG4CPLUS_INCLUDES@ LOG4CPLUS_LIBS = @LOG4CPLUS_LIBS@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ MYSQL_LIBS = @MYSQL_LIBS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PERL = @PERL@ PGSQL_CPPFLAGS = @PGSQL_CPPFLAGS@ PGSQL_LIBS = @PGSQL_LIBS@ PKG_CONFIG = @PKG_CONFIG@ PLANTUML = @PLANTUML@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SEP = @SEP@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ USE_LCOV = @USE_LCOV@ VALGRIND = @VALGRIND@ VERSION = @VERSION@ WARNING_GCC_44_STRICT_ALIASING_CFLAG = @WARNING_GCC_44_STRICT_ALIASING_CFLAG@ XSLTPROC = @XSLTPROC@ YACC = @YACC@ YFLAGS = @YFLAGS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ SUBDIRS = . tests AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib \ $(BOOST_INCLUDES) BUILT_SOURCES = config_messages.h config_messages.cc lib_LTLIBRARIES = libkea-cfgclient.la libkea_cfgclient_la_SOURCES = config_data.h config_data.cc \ module_spec.h module_spec.cc command_mgr.cc command_mgr.h \ command_socket.cc command_socket.h command_socket_factory.cc \ command_socket_factory.h config_log.h config_log.cc libkea_cfgclient_la_LIBADD = \ $(top_builddir)/src/lib/dhcp/libkea-dhcp++.la \ $(top_builddir)/src/lib/asiolink/libkea-asiolink.la \ $(top_builddir)/src/lib/cc/libkea-cc.la \ $(top_builddir)/src/lib/dns/libkea-dns++.la \ $(top_builddir)/src/lib/cryptolink/libkea-cryptolink.la \ $(top_builddir)/src/lib/log/libkea-log.la \ $(top_builddir)/src/lib/util/threads/libkea-threads.la \ $(top_builddir)/src/lib/util/libkea-util.la \ $(top_builddir)/src/lib/exceptions/libkea-exceptions.la \ $(LOG4CPLUS_LIBS) $(CRYPTO_LIBS) libkea_cfgclient_la_LDFLAGS = -no-undefined -version-info 2:1:0 \ $(CRYPTO_LDFLAGS) nodist_libkea_cfgclient_la_SOURCES = config_messages.h config_messages.cc # The message file should be in the distribution. EXTRA_DIST = config_messages.mes command-socket.dox CLEANFILES = *.gcno *.gcda config_messages.h config_messages.cc s-messages all: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) all-recursive .SUFFIXES: .SUFFIXES: .cc .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/lib/config/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign src/lib/config/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } libkea-cfgclient.la: $(libkea_cfgclient_la_OBJECTS) $(libkea_cfgclient_la_DEPENDENCIES) $(EXTRA_libkea_cfgclient_la_DEPENDENCIES) $(AM_V_CXXLD)$(libkea_cfgclient_la_LINK) -rpath $(libdir) $(libkea_cfgclient_la_OBJECTS) $(libkea_cfgclient_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/command_mgr.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/command_socket.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/command_socket_factory.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/config_data.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/config_log.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/config_messages.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/module_spec.Plo@am__quote@ .cc.o: @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $< .cc.obj: @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .cc.lo: @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs # This directory's subdirectories are mostly independent; you can cd # into them and run 'make' without going through this Makefile. # To change the values of 'make' variables: instead of editing Makefiles, # (1) if the variable is set in 'config.status', edit 'config.status' # (which will cause the Makefiles to be regenerated when you run 'make'); # (2) otherwise, pass the desired values on the 'make' command line. $(am__recursive_targets): @fail=; \ if $(am__make_keepgoing); then \ failcom='fail=yes'; \ else \ failcom='exit 1'; \ fi; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-recursive CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-recursive cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done check-am: all-am check: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) check-recursive all-am: Makefile $(LTLIBRARIES) installdirs: installdirs-recursive installdirs-am: for dir in "$(DESTDIR)$(libdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) clean: clean-recursive clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ mostlyclean-am distclean: distclean-recursive -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-libLTLIBRARIES install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: uninstall-libLTLIBRARIES .MAKE: $(am__recursive_targets) all check install install-am \ install-strip .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ check-am clean clean-generic clean-libLTLIBRARIES \ clean-libtool cscopelist-am ctags ctags-am distclean \ distclean-compile distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am \ install-libLTLIBRARIES install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs installdirs-am maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am uninstall-libLTLIBRARIES # Define rule to build logging source files from message file config_messages.h config_messages.cc: s-messages s-messages: config_messages.mes $(top_builddir)/src/lib/log/compiler/kea-msg-compiler $(top_srcdir)/src/lib/config/config_messages.mes touch $@ # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: kea-1.1.0/src/lib/config/command_socket_factory.h0000664000175000017500000000202212772017075016670 00000000000000// Copyright (C) 2015 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 COMMAND_SOCKET_FACTORY_H #define COMMAND_SOCKET_FACTORY_H #include #include namespace isc { namespace config { /// A factory class for opening command socket /// /// This class provides an interface for opening command socket. class CommandSocketFactory { public: /// @brief Creates a socket specified by socket_info structure /// /// /// Currently supported types are: /// - unix /// /// See @ref CommandMgr::openCommandSocket for detailed description. /// @throw CommandSocketError /// /// @param socket_info structure that describes the socket /// @return socket descriptor static CommandSocketPtr create(const isc::data::ConstElementPtr& socket_info); }; }; }; #endif kea-1.1.0/src/lib/config/config_data.cc0000664000175000017500000002076512772017075014565 00000000000000// Copyright (C) 2009-2015 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 #include #include #include using namespace isc::data; namespace { // Returns the '_spec' part of a list or map specification (recursively, // i.e. if it is a list of lists or maps, will return the spec of the // inner-most list or map). // // \param spec_part the list or map specification (part) // \return the value of spec_part's "list_item_spec" or "map_item_spec", // or the original spec_part, if it is not a MapElement or does // not contain "list_item_spec" or "map_item_spec" ConstElementPtr findListOrMapSubSpec(ConstElementPtr spec_part) { while (spec_part->getType() == Element::map && (spec_part->contains("list_item_spec") || spec_part->contains("map_item_spec"))) { if (spec_part->contains("list_item_spec")) { spec_part = spec_part->get("list_item_spec"); } else { spec_part = spec_part->get("map_item_spec"); } } return spec_part; } // Returns a specific Element in a given specification ListElement // // \exception DataNotFoundError if the given identifier does not // point to an existing element. Since we are dealing with the // specification here, and not the config data itself, this should // not happen, and is a code bug. // // \param spec_part ListElement to find the element in // \param id_part the name of the element to find (must match the value // "item_name" in the list item // \param id_full the full identifier id_part is a part of, this is // used to better report any errors ConstElementPtr findItemInSpecList(ConstElementPtr spec_part, const std::string& id_part, const std::string& id_full) { bool found = false; BOOST_FOREACH(ConstElementPtr list_el, spec_part->listValue()) { if (list_el->getType() == Element::map && list_el->contains("item_name") && list_el->get("item_name")->stringValue() == id_part) { spec_part = list_el; found = true; } } if (!found) { isc_throw(isc::config::DataNotFoundError, id_part + " in " + id_full + " not found"); } return (spec_part); } } // anonymous namespace namespace isc { namespace config { // // Return a part of a specification, as identified by the // '/'-separated identifier. // If it cannot be found, a DataNotFound error is thrown. // // Recursively goes through the Element. If it is a List, // we search it contents to have 'items' (i.e. contain item_name) // If it is a map, we search through the list contained in its // 'map_item_spec' value. This code assumes the data has been // validated and conforms to the specification. static ConstElementPtr find_spec_part(ConstElementPtr spec, const std::string& identifier) { if (!spec) { isc_throw(DataNotFoundError, "Empty specification"); } ConstElementPtr spec_part = spec; if (identifier == "") { isc_throw(DataNotFoundError, "Empty identifier"); } std::string id = identifier; size_t sep = id.find('/'); while(sep != std::string::npos) { std::string part = id.substr(0, sep); if (spec_part->getType() == Element::list) { spec_part = findItemInSpecList(spec_part, part, identifier); } else { isc_throw(DataNotFoundError, "Not a list of spec items: " + spec_part->str()); } id = id.substr(sep + 1); sep = id.find("/"); // As long as we are not in the 'final' element as specified // by the identifier, we want to automatically traverse list // and map specifications if (id != "" && id != "/") { spec_part = findListOrMapSubSpec(spec_part); } } if (id != "" && id != "/") { if (spec_part->getType() == Element::list) { spec_part = findItemInSpecList(spec_part, id, identifier); } else if (spec_part->getType() == Element::map) { if (spec_part->contains("map_item_spec")) { spec_part = findItemInSpecList( spec_part->get("map_item_spec"), id, identifier); } else { // Either we already have the element we are looking // for, or we are trying to reach something that does // not exist (i.e. the code does not match the spec) if (!spec_part->contains("item_name") || spec_part->get("item_name")->stringValue() != id) { isc_throw(DataNotFoundError, "Element above " + id + " in " + identifier + " is not a map: " + spec_part->str()); } } } } return (spec_part); } // // Adds the names of the items in the given specification part. // If recurse is true, maps will also have their children added. // Result must be a ListElement // static void spec_name_list(ElementPtr result, ConstElementPtr spec_part, const std::string& prefix, bool recurse = false) { if (spec_part->getType() == Element::list) { BOOST_FOREACH(ConstElementPtr list_el, spec_part->listValue()) { if (list_el->getType() == Element::map && list_el->contains("item_name")) { std::string new_prefix = prefix; if (prefix != "") { new_prefix += "/"; } new_prefix += list_el->get("item_name")->stringValue(); if (recurse && list_el->get("item_type")->stringValue() == "map") { spec_name_list(result, list_el->get("map_item_spec"), new_prefix, recurse); } else { result->add(Element::create(new_prefix)); } } } } else if (spec_part->getType() == Element::map && spec_part->contains("map_item_spec")) { spec_name_list(result, spec_part->get("map_item_spec"), prefix, recurse); } } ConstElementPtr ConfigData::getValue(const std::string& identifier) const { // 'fake' is set, but dropped by this function and // serves no further purpose. bool fake; return (getValue(fake, identifier)); } ConstElementPtr ConfigData::getValue(bool& is_default, const std::string& identifier) const { ConstElementPtr value = _config->find(identifier); if (value) { is_default = false; } else { ConstElementPtr spec_part = find_spec_part(_module_spec.getConfigSpec(), identifier); if (spec_part->contains("item_default")) { value = spec_part->get("item_default"); is_default = true; } else { is_default = false; value = ElementPtr(); } } return (value); } ConstElementPtr ConfigData::getDefaultValue(const std::string& identifier) const { ConstElementPtr spec_part = find_spec_part(_module_spec.getConfigSpec(), identifier); if (spec_part->contains("item_default")) { return spec_part->get("item_default"); } else { isc_throw(DataNotFoundError, "No default for " + identifier); } } /// Returns an ElementPtr pointing to a ListElement containing /// StringElements with the names of the options at the given /// identifier. If recurse is true, maps will be expanded as well ConstElementPtr ConfigData::getItemList(const std::string& identifier, bool recurse) const { ElementPtr result = Element::createList(); ConstElementPtr spec_part = getModuleSpec().getConfigSpec(); if (identifier != "" && identifier != "/") { spec_part = find_spec_part(spec_part, identifier); } spec_name_list(result, spec_part, identifier, recurse); return (result); } /// Returns an ElementPtr containing a MapElement with identifier->value /// pairs. ConstElementPtr ConfigData::getFullConfig() const { ElementPtr result = Element::createMap(); ConstElementPtr items = getItemList("", false); BOOST_FOREACH(ConstElementPtr item, items->listValue()) { result->set(item->stringValue(), getValue(item->stringValue())); } return (result); } } } kea-1.1.0/src/lib/config/command_socket.cc0000664000175000017500000000247012772017075015306 00000000000000// Copyright (C) 2015 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 #include #include #include #include #include namespace isc { namespace config { ConnectionSocket::ConnectionSocket(int sockfd) { sockfd_ = sockfd; // Install commandReader callback. When there's any data incoming on this // socket, commandReader will be called and process it. It may also // eventually close this socket. isc::dhcp::IfaceMgr::instance().addExternalSocket(sockfd, boost::bind(&ConnectionSocket::receiveHandler, this)); } void ConnectionSocket::close() { LOG_INFO(command_logger, COMMAND_SOCKET_CONNECTION_CLOSED).arg(sockfd_); // Unregister this callback isc::dhcp::IfaceMgr::instance().deleteExternalSocket(sockfd_); // We're closing a connection, not the whole socket. It's ok to just // close the connection and don't delete anything. ::close(sockfd_); } void ConnectionSocket::receiveHandler() { CommandMgr::instance().commandReader(sockfd_); } }; }; kea-1.1.0/src/lib/config/Makefile.am0000664000175000017500000000370612772445242014051 00000000000000SUBDIRS = . tests AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib AM_CPPFLAGS += $(BOOST_INCLUDES) # Define rule to build logging source files from message file config_messages.h config_messages.cc: s-messages s-messages: config_messages.mes $(top_builddir)/src/lib/log/compiler/kea-msg-compiler $(top_srcdir)/src/lib/config/config_messages.mes touch $@ BUILT_SOURCES = config_messages.h config_messages.cc lib_LTLIBRARIES = libkea-cfgclient.la libkea_cfgclient_la_SOURCES = config_data.h config_data.cc libkea_cfgclient_la_SOURCES += module_spec.h module_spec.cc libkea_cfgclient_la_SOURCES += command_mgr.cc command_mgr.h libkea_cfgclient_la_SOURCES += command_socket.cc command_socket.h libkea_cfgclient_la_SOURCES += command_socket_factory.cc command_socket_factory.h libkea_cfgclient_la_SOURCES += config_log.h config_log.cc libkea_cfgclient_la_LIBADD = $(top_builddir)/src/lib/dhcp/libkea-dhcp++.la libkea_cfgclient_la_LIBADD += $(top_builddir)/src/lib/asiolink/libkea-asiolink.la libkea_cfgclient_la_LIBADD += $(top_builddir)/src/lib/cc/libkea-cc.la libkea_cfgclient_la_LIBADD += $(top_builddir)/src/lib/dns/libkea-dns++.la libkea_cfgclient_la_LIBADD += $(top_builddir)/src/lib/cryptolink/libkea-cryptolink.la libkea_cfgclient_la_LIBADD += $(top_builddir)/src/lib/log/libkea-log.la libkea_cfgclient_la_LIBADD += $(top_builddir)/src/lib/util/threads/libkea-threads.la libkea_cfgclient_la_LIBADD += $(top_builddir)/src/lib/util/libkea-util.la libkea_cfgclient_la_LIBADD += $(top_builddir)/src/lib/exceptions/libkea-exceptions.la libkea_cfgclient_la_LIBADD += $(LOG4CPLUS_LIBS) $(CRYPTO_LIBS) libkea_cfgclient_la_LDFLAGS = -no-undefined -version-info 2:1:0 libkea_cfgclient_la_LDFLAGS += $(CRYPTO_LDFLAGS) nodist_libkea_cfgclient_la_SOURCES = config_messages.h config_messages.cc # The message file should be in the distribution. EXTRA_DIST = config_messages.mes command-socket.dox CLEANFILES = *.gcno *.gcda config_messages.h config_messages.cc s-messages kea-1.1.0/src/lib/config/config_log.h0000664000175000017500000000152112772017075014264 00000000000000// Copyright (C) 2011-2015 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 CONFIG_LOG_H #define CONFIG_LOG_H #include #include "config_messages.h" namespace isc { namespace config { /// @brief Command processing Logger /// /// Define the logger used to log messages related to command processing. /// We could define it in multiple modules, but defining in a single /// module and linking to it saves time and space. extern isc::log::Logger command_logger; // Enumerate configuration elements as they are processed. const int DBG_COMMAND = DBGLVL_COMMAND; } // namespace config } // namespace isc #endif // CONFIG_LOG_H kea-1.1.0/src/lib/config/module_spec.cc0000664000175000017500000003670512772017075014627 00000000000000// Copyright (C) 2010-2015 Internet Systems Consortium. // // 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 #include #include #include #include #include // todo: add more context to thrown ModuleSpecErrors? using namespace isc::data; using namespace isc::config; namespace { // // Private functions // void check_leaf_item(ConstElementPtr spec, const std::string& name, Element::types type, bool mandatory) { if (spec->contains(name)) { if (type == Element::any || spec->get(name)->getType() == type) { return; } else { isc_throw(ModuleSpecError, name + " not of type " + Element::typeToName(type)); } } else if (mandatory) { // todo: want parent item name, and perhaps some info about location // in list? or just catch and throw new... // or make this part non-throwing and check return value... isc_throw(ModuleSpecError, name + " missing in " + spec->str()); } } void check_config_item_list(ConstElementPtr spec); void check_config_item(ConstElementPtr spec) { check_leaf_item(spec, "item_name", Element::string, true); check_leaf_item(spec, "item_type", Element::string, true); check_leaf_item(spec, "item_optional", Element::boolean, true); check_leaf_item(spec, "item_default", Element::nameToType(spec->get("item_type")->stringValue()), !spec->get("item_optional")->boolValue() ); // if list, check the list specification if (Element::nameToType(spec->get("item_type")->stringValue()) == Element::list) { check_leaf_item(spec, "list_item_spec", Element::map, true); check_config_item(spec->get("list_item_spec")); } if (spec->get("item_type")->stringValue() == "map") { check_leaf_item(spec, "map_item_spec", Element::list, true); check_config_item_list(spec->get("map_item_spec")); } else if (spec->get("item_type")->stringValue() == "named_set") { check_leaf_item(spec, "named_set_item_spec", Element::map, true); check_config_item(spec->get("named_set_item_spec")); } } void check_config_item_list(ConstElementPtr spec) { if (spec->getType() != Element::list) { isc_throw(ModuleSpecError, "config_data is not a list of elements"); } BOOST_FOREACH(ConstElementPtr item, spec->listValue()) { check_config_item(item); } } // checks whether the given element is a valid statistics specification // returns false if the specification is bad bool check_format(ConstElementPtr value, ConstElementPtr format_name) { typedef std::map format_types; format_types time_formats; // TODO: should be added other format types if necessary time_formats.insert( format_types::value_type("date-time", "%Y-%m-%dT%H:%M:%SZ") ); time_formats.insert( format_types::value_type("date", "%Y-%m-%d") ); time_formats.insert( format_types::value_type("time", "%H:%M:%S") ); BOOST_FOREACH (const format_types::value_type& f, time_formats) { if (format_name->stringValue() == f.first) { struct tm tm; std::vector buf(32); memset(&tm, 0, sizeof(tm)); // reverse check return (strptime(value->stringValue().c_str(), f.second.c_str(), &tm) != NULL && strftime(&buf[0], buf.size(), f.second.c_str(), &tm) != 0 && strncmp(value->stringValue().c_str(), &buf[0], buf.size()) == 0); } } return (false); } void check_statistics_item_list(ConstElementPtr spec); void check_statistics_item_list(ConstElementPtr spec) { if (spec->getType() != Element::list) { isc_throw(ModuleSpecError, "statistics is not a list of elements"); } BOOST_FOREACH(ConstElementPtr item, spec->listValue()) { check_config_item(item); // additional checks for statistics check_leaf_item(item, "item_title", Element::string, true); check_leaf_item(item, "item_description", Element::string, true); check_leaf_item(item, "item_format", Element::string, false); // checks name of item_format and validation of item_default if (item->contains("item_format") && item->contains("item_default")) { if(!check_format(item->get("item_default"), item->get("item_format"))) { isc_throw(ModuleSpecError, "item_default not valid type of item_format"); } } } } void check_command(ConstElementPtr spec) { check_leaf_item(spec, "command_name", Element::string, true); check_leaf_item(spec, "command_args", Element::list, true); check_config_item_list(spec->get("command_args")); } void check_command_list(ConstElementPtr spec) { if (spec->getType() != Element::list) { isc_throw(ModuleSpecError, "commands is not a list of elements"); } BOOST_FOREACH(ConstElementPtr item, spec->listValue()) { check_command(item); } } void check_data_specification(ConstElementPtr spec) { check_leaf_item(spec, "module_name", Element::string, true); check_leaf_item(spec, "module_description", Element::string, false); // config_data is not mandatory; module could just define // commands and have no config if (spec->contains("config_data")) { check_config_item_list(spec->get("config_data")); } if (spec->contains("commands")) { check_command_list(spec->get("commands")); } if (spec->contains("statistics")) { check_statistics_item_list(spec->get("statistics")); } } // checks whether the given element is a valid module specification // throws a ModuleSpecError if the specification is bad void check_module_specification(ConstElementPtr def) { try { check_data_specification(def); } catch (const TypeError& te) { isc_throw(ModuleSpecError, te.what()); } } } namespace isc { namespace config { // // Public functions // ModuleSpec::ModuleSpec(ConstElementPtr module_spec_element, const bool check) throw(ModuleSpecError) { module_specification = module_spec_element; if (check) { check_module_specification(module_specification); } } ConstElementPtr ModuleSpec::getCommandsSpec() const { if (module_specification->contains("commands")) { return (module_specification->get("commands")); } else { return (ElementPtr()); } } ConstElementPtr ModuleSpec::getConfigSpec() const { if (module_specification->contains("config_data")) { return (module_specification->get("config_data")); } else { return (ElementPtr()); } } ConstElementPtr ModuleSpec::getStatisticsSpec() const { if (module_specification->contains("statistics")) { return (module_specification->get("statistics")); } else { return (ElementPtr()); } } const std::string ModuleSpec::getModuleName() const { return (module_specification->get("module_name")->stringValue()); } const std::string ModuleSpec::getModuleDescription() const { if (module_specification->contains("module_description")) { return (module_specification->get("module_description")->stringValue()); } else { return (std::string("")); } } bool ModuleSpec::validateConfig(ConstElementPtr data, const bool full) const { ConstElementPtr spec = module_specification->find("config_data"); return (validateSpecList(spec, data, full, ElementPtr())); } bool ModuleSpec::validateStatistics(ConstElementPtr data, const bool full) const { ConstElementPtr spec = module_specification->find("statistics"); return (validateSpecList(spec, data, full, ElementPtr())); } bool ModuleSpec::validateCommand(const std::string& command, ConstElementPtr args, ElementPtr errors) const { if (args->getType() != Element::map) { errors->add(Element::create("args for command " + command + " is not a map")); return (false); } ConstElementPtr commands_spec = module_specification->find("commands"); if (!commands_spec) { // there are no commands according to the spec. errors->add(Element::create("The given module has no commands")); return (false); } BOOST_FOREACH(ConstElementPtr cur_command, commands_spec->listValue()) { if (cur_command->get("command_name")->stringValue() == command) { return (validateSpecList(cur_command->get("command_args"), args, true, errors)); } } // this command is unknown errors->add(Element::create("Unknown command " + command)); return (false); } bool ModuleSpec::validateConfig(ConstElementPtr data, const bool full, ElementPtr errors) const { ConstElementPtr spec = module_specification->find("config_data"); return (validateSpecList(spec, data, full, errors)); } bool ModuleSpec::validateStatistics(ConstElementPtr data, const bool full, ElementPtr errors) const { ConstElementPtr spec = module_specification->find("statistics"); return (validateSpecList(spec, data, full, errors)); } ModuleSpec moduleSpecFromFile(const std::string& file_name, const bool check) throw(JSONError, ModuleSpecError) { std::ifstream file; // zero out the errno to be safe errno = 0; file.open(file_name.c_str()); if (!file) { std::stringstream errs; errs << "Error opening " << file_name << ": " << strerror(errno); isc_throw(ModuleSpecError, errs.str()); } ConstElementPtr module_spec_element = Element::fromJSON(file, file_name); if (module_spec_element->contains("module_spec")) { return (ModuleSpec(module_spec_element->get("module_spec"), check)); } else { isc_throw(ModuleSpecError, "No module_spec in specification"); } } ModuleSpec moduleSpecFromFile(std::ifstream& in, const bool check) throw(JSONError, ModuleSpecError) { ConstElementPtr module_spec_element = Element::fromJSON(in); if (module_spec_element->contains("module_spec")) { return (ModuleSpec(module_spec_element->get("module_spec"), check)); } else { isc_throw(ModuleSpecError, "No module_spec in specification"); } } namespace { // // private functions // // // helper functions for validation // bool check_type(ConstElementPtr spec, ConstElementPtr element) { std::string cur_item_type; cur_item_type = spec->get("item_type")->stringValue(); if (cur_item_type == "any") { return (true); } switch (element->getType()) { case Element::integer: return (cur_item_type == "integer"); break; case Element::real: return (cur_item_type == "real"); break; case Element::boolean: return (cur_item_type == "boolean"); break; case Element::string: return (cur_item_type == "string"); break; case Element::list: return (cur_item_type == "list"); break; case Element::map: return (cur_item_type == "map" || cur_item_type == "named_set"); break; } return (false); } } bool ModuleSpec::validateItem(ConstElementPtr spec, ConstElementPtr data, const bool full, ElementPtr errors) const { if (!check_type(spec, data)) { // we should do some proper error feedback here // std::cout << "type mismatch; not " << spec->get("item_type") << ": " << data << std::endl; // std::cout << spec << std::endl; if (errors) { errors->add(Element::create("Type mismatch")); } return (false); } if (data->getType() == Element::list) { ConstElementPtr list_spec = spec->get("list_item_spec"); BOOST_FOREACH(ConstElementPtr list_el, data->listValue()) { if (!check_type(list_spec, list_el)) { if (errors) { errors->add(Element::create("Type mismatch")); } return (false); } if (list_spec->get("item_type")->stringValue() == "map") { if (!validateItem(list_spec, list_el, full, errors)) { return (false); } } } } if (data->getType() == Element::map) { // either a normal 'map' or a 'named set' (determined by which // subspecification it has) if (spec->contains("map_item_spec")) { if (!validateSpecList(spec->get("map_item_spec"), data, full, errors)) { return (false); } } else { typedef std::pair maptype; BOOST_FOREACH(maptype m, data->mapValue()) { if (!validateItem(spec->get("named_set_item_spec"), m.second, full, errors)) { return (false); } } } } if (spec->contains("item_format")) { if (!check_format(data, spec->get("item_format"))) { if (errors) { errors->add(Element::create("Format mismatch")); } return (false); } } return (true); } // spec is a map with item_name etc, data is a map bool ModuleSpec::validateSpec(ConstElementPtr spec, ConstElementPtr data, const bool full, ElementPtr errors) const { std::string item_name = spec->get("item_name")->stringValue(); bool optional = spec->get("item_optional")->boolValue(); ConstElementPtr data_el; data_el = data->get(item_name); if (data_el) { if (!validateItem(spec, data_el, full, errors)) { return (false); } } else { if (!optional && full) { if (errors) { errors->add(Element::create("Non-optional value missing")); } return (false); } } return (true); } // spec is a list of maps, data is a map bool ModuleSpec::validateSpecList(ConstElementPtr spec, ConstElementPtr data, const bool full, ElementPtr errors) const { bool validated = true; BOOST_FOREACH(ConstElementPtr cur_spec_el, spec->listValue()) { if (!validateSpec(cur_spec_el, data, full, errors)) { validated = false; } } typedef std::pair maptype; BOOST_FOREACH(maptype m, data->mapValue()) { // Ignore 'version' as a config element if (m.first.compare("version") != 0) { bool found = false; BOOST_FOREACH(ConstElementPtr cur_spec_el, spec->listValue()) { if (cur_spec_el->get("item_name")->stringValue().compare(m.first) == 0) { found = true; } } if (!found) { validated = false; if (errors) { errors->add(Element::create("Unknown item " + m.first)); } } } } return (validated); } } } kea-1.1.0/src/lib/config/config_messages.mes0000664000175000017500000001144412772742501015653 00000000000000# Copyright (C) 2011-2015 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::config % COMMAND_DEREGISTERED Command %1 deregistered This debug message indicates that the daemon stopped supporting specified command. This command can no longer be issued. If the command socket is open and this command is issued, the daemon will not be able to process it. % COMMAND_PROCESS_ERROR1 Error while processing command: %1 This warning message indicates that the server encountered an error while processing received command. Additional information will be provided, if available. Additional log messages may provide more details. % COMMAND_PROCESS_ERROR2 Error while processing command: %1 This warning message indicates that the server encountered an error while processing received command. The difference, compared to COMMAND_PROCESS_ERROR1 is that the initial command was well formed and the error occurred during logic processing, not the command parsing. Additional information will be provided, if available. Additional log messages may provide more details. % COMMAND_RECEIVED Received command '%1' This informational message indicates that a command was received over command socket. The nature of this command and its possible results will be logged with separate messages. % COMMAND_REGISTERED Command %1 registered This debug message indicates that the daemon started supporting specified command. If the command socket is open, this command can now be issued. % COMMAND_RESPONSE_ERROR Server failed to generate response for command: %1 This error message indicates that the server failed to generate response for specified command. This likely indicates a server logic error, as the server is expected to generate valid responses for all commands, even malformed ones. % COMMAND_SOCKET_ACCEPT_FAIL Failed to accept incoming connection on command socket %1: %2 This error indicates that the server detected incoming connection and executed accept system call on said socket, but this call returned an error. Additional information may be provided by the system as second parameter. % COMMAND_SOCKET_CONNECTION_CLOSED Closed socket %1 for existing command connection This is an informational message that the socket created for handling client's connection is closed. This usually means that the client disconnected, but may also mean a timeout. % COMMAND_SOCKET_CONNECTION_OPENED Opened socket %1 for incoming command connection on socket %2 This is an informational message that a new incoming command connection was detected and a dedicated socket was opened for that connection. % COMMAND_SOCKET_FAIL_NONBLOCK Failed to set non-blocking mode for socket %1 created for incoming connection on socket %2: %3 This error message indicates that the server failed to set non-blocking mode on just created socket. That socket was created for accepting specific incoming connection. Additional information may be provided as third parameter. % COMMAND_SOCKET_READ Received %1 bytes over command socket %2 This debug message indicates that specified number of bytes was received over command socket identified by specified file descriptor. % COMMAND_SOCKET_READ_FAIL Encountered error %1 while reading from command socket %2 This error message indicates that an error was encountered while reading from command socket. % COMMAND_SOCKET_RESPONSE_TOOLARGE Server's response was larger (%1) than supported 64KB This error message indicates that the server received a command and generated an answer for it, but that response was larger than supported 64KB. Server will attempt to send the first 64KB of the response. Depending on the nature of this response, this may indicate a software or configuration error. Future Kea versions are expected to have better support for large responses. % COMMAND_SOCKET_UNIX_CLOSE Command socket closed: UNIX, fd=%1, path=%2 This informational message indicates that the daemon closed a command processing socket. This was a UNIX socket. It was opened with the file descriptor and path specified. % COMMAND_SOCKET_UNIX_OPEN Command socket opened: UNIX, fd=%1, path=%2 This informational message indicates that the daemon opened a command processing socket. This is a UNIX socket. It was opened with the file descriptor and path specified. % COMMAND_SOCKET_WRITE Sent response of %1 bytes over command socket %2 This debug message indicates that the specified number of bytes was sent over command socket identifier by the specified file descriptor. % COMMAND_SOCKET_WRITE_FAIL Error while writing %1 bytes to command socket %2 This error message indicates that an error was encountered while attempting to send a response to the command socket. kea-1.1.0/src/lib/config/command_socket_factory.cc0000664000175000017500000002033712772017075017037 00000000000000// Copyright (C) 2015 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 #include #include #include #include #include #include #include #include #include #include using namespace isc::data; namespace isc { namespace config { /// @brief Wrapper for UNIX stream sockets /// /// There are two UNIX socket types: datagram-based (equivalent of UDP) and /// stream-based (equivalent of TCP). This class represents stream-based /// sockets. It opens up a unix-socket and waits for incoming connections. /// Once incoming connection is detected, accept() system call is called /// and a new socket for that particular connection is returned. A new /// object of @ref ConnectionSocket is created. class UnixCommandSocket : public CommandSocket { public: /// @brief Default constructor /// /// Opens specified UNIX socket. /// /// @param filename socket filename UnixCommandSocket(const std::string& filename) : filename_(filename) { // Create the socket and set it up. sockfd_ = createUnixSocket(filename_); // Install this socket in Interface Manager. isc::dhcp::IfaceMgr::instance().addExternalSocket(sockfd_, boost::bind(&UnixCommandSocket::receiveHandler, this)); } private: /// @brief Auxiliary method for creating a UNIX socket /// /// @param file_name specifies socket file path /// @return socket file descriptor int createUnixSocket(const std::string& file_name) { struct sockaddr_un addr; // string.size() returns number of bytes (without trailing zero) // we need 1 extra byte for terminating 0. if (file_name.size() > sizeof(addr.sun_path) - 1) { isc_throw(SocketError, "Failed to open socket: path specified (" << file_name << ") is longer (" << file_name.size() << " bytes) than allowed " << (sizeof(addr.sun_path) - 1) << " bytes."); } int fd = socket(AF_UNIX, SOCK_STREAM, 0); if (fd == -1) { isc_throw(isc::config::SocketError, "Failed to create AF_UNIX socket:" << strerror(errno)); } // Let's remove the old file. We don't care about any possible // errors here. The file should not be there if the file was // shut down properly. static_cast(remove(file_name.c_str())); // Set this socket to be closed-on-exec. if (fcntl(fd, F_SETFD, FD_CLOEXEC) != 0) { const char* errmsg = strerror(errno); ::close(fd); isc_throw(SocketError, "Failed to set close-on-exec on unix socket\ " << fd << ": " << errmsg); } // Set this socket to be non-blocking one. if (fcntl(fd, F_SETFL, O_NONBLOCK) != 0) { const char* errmsg = strerror(errno); ::close(fd); isc_throw(SocketError, "Failed to set non-block mode on unix socket " << fd << ": " << errmsg); } // Now bind the socket to the specified path. memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; strncpy(addr.sun_path, file_name.c_str(), sizeof(addr.sun_path) - 1); if (bind(fd, (struct sockaddr*)&addr, sizeof(addr))) { const char* errmsg = strerror(errno); ::close(fd); static_cast(remove(file_name.c_str())); isc_throw(isc::config::SocketError, "Failed to bind socket " << fd << " to " << file_name << ": " << errmsg); } // One means that we allow at most 1 awaiting connections. // Any additional attempts will get ECONNREFUSED error. // That means that at any given time, there may be at most one controlling // connection. /// @todo: Make the number of parallel connections configurable. int status = listen(fd, 1); if (status < 0) { const char* errmsg = strerror(errno); ::close(fd); static_cast(remove(file_name.c_str())); isc_throw(isc::config::SocketError, "Failed to listen on socket fd=" << fd << ", filename=" << file_name << ": " << errmsg); } // Woohoo! Socket opened, let's log it! LOG_INFO(command_logger, COMMAND_SOCKET_UNIX_OPEN).arg(fd).arg(file_name); return (fd); } /// @public /// @brief Connection acceptor, a callback used to accept incoming connections. /// /// This callback is used on a control socket. Once called, it will accept /// incoming connection, create a new socket for it and create an instance /// of ConnectionSocket, which will take care of the rest (i.e. install /// appropriate callback for that new socket in @ref isc::dhcp::IfaceMgr). void receiveHandler() { // This method is specific to receiving data over UNIX socket, so using // sockaddr_un instead of sockaddr_storage here is ok. struct sockaddr_un client_addr; socklen_t client_addr_len; client_addr_len = sizeof(client_addr); // Accept incoming connection. This will create a separate socket for // handling this specific connection. int fd2 = accept(sockfd_, reinterpret_cast(&client_addr), &client_addr_len); if (fd2 == -1) { LOG_ERROR(command_logger, COMMAND_SOCKET_ACCEPT_FAIL) .arg(sockfd_).arg(strerror(errno)); return; } // And now create an object that represents that new connection. CommandSocketPtr conn(new ConnectionSocket(fd2)); // Not sure if this is really needed, but let's set it to non-blocking // mode. if (fcntl(fd2, F_SETFL, O_NONBLOCK) != 0) { // Failed to set socket to non-blocking mode. LOG_ERROR(command_logger, COMMAND_SOCKET_FAIL_NONBLOCK) .arg(fd2).arg(sockfd_).arg(strerror(errno)); conn.reset(); return; } // Remember this socket descriptor. It will be needed when we shut down // the server. CommandMgr::instance().addConnection(conn); LOG_INFO(command_logger, COMMAND_SOCKET_CONNECTION_OPENED).arg(fd2) .arg(sockfd_); } /// @private // This method is called when we shutdown the connection. void close() { LOG_INFO(command_logger, COMMAND_SOCKET_UNIX_CLOSE).arg(sockfd_) .arg(filename_); isc::dhcp::IfaceMgr::instance().deleteExternalSocket(sockfd_); // Close should always succeed. We don't care if we're able to delete // the socket or not. ::close(sockfd_); static_cast(remove(filename_.c_str())); } /// @brief UNIX filename representing this socket std::string filename_; }; CommandSocketPtr CommandSocketFactory::create(const isc::data::ConstElementPtr& socket_info) { if(!socket_info) { isc_throw(BadSocketInfo, "Missing socket_info parameters, can't create socket."); } ConstElementPtr type = socket_info->get("socket-type"); if (!type) { isc_throw(BadSocketInfo, "Mandatory 'socket-type' parameter missing"); } if (type->stringValue() == "unix") { // UNIX socket is requested. It takes one parameter: socket-name that // specifies UNIX path of the socket. ConstElementPtr name = socket_info->get("socket-name"); if (!name) { isc_throw(BadSocketInfo, "Mandatory 'socket-name' parameter missing"); } if (name->getType() != Element::string) { isc_throw(BadSocketInfo, "'socket-name' parameter expected to be a string"); } return (CommandSocketPtr(new UnixCommandSocket(name->stringValue()))); } else { isc_throw(BadSocketInfo, "Specified socket type ('" + type->stringValue() + "') is not supported."); } } }; }; kea-1.1.0/src/lib/config/command_socket.h0000664000175000017500000000622012772017075015145 00000000000000// Copyright (C) 2015 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 COMMAND_SOCKET_H #define COMMAND_SOCKET_H #include #include namespace isc { namespace config { /// @brief An exception indicating that specified socket parameters are invalid class BadSocketInfo : public Exception { public: BadSocketInfo(const char* file, size_t line, const char* what) : isc::Exception(file, line, what) { }; }; /// @brief An exception indicating a problem with socket operation class SocketError : public Exception { public: SocketError(const char* file, size_t line, const char* what) : isc::Exception(file, line, what) { }; }; /// @brief Abstract base class that represents an open command socket /// /// Derived classes are expected to handle specific socket types (e.g. UNIX /// or https). /// /// For derived classes, see @ref UnixCommandSocket for a socket that /// accepts connections over UNIX socket and @ref ConnectionSocket that /// handles established connections (currently over UNIX sockets, but /// should be generic). class CommandSocket { public: /// @brief Method used to handle incoming data /// /// This may be registered in @ref isc::dhcp::IfaceMgr virtual void receiveHandler() = 0; /// @brief General method for closing socket. /// /// This is the default implementation that simply closes /// the socket. Derived classes may do additional steps /// to terminate the connection. virtual void close() { ::close(sockfd_); } /// @brief Virtual destructor. virtual ~CommandSocket() { close(); } /// @brief Returns socket descriptor. int getFD() const { return (sockfd_); } protected: /// Stores socket descriptor. int sockfd_; }; /// Pointer to a command socket object typedef boost::shared_ptr CommandSocketPtr; /// @brief This class represents a streaming socket for handling connections /// /// Initially a socket (e.g. UNIX) is opened (represented by other classes, e.g. /// @ref UnixCommandSocket). Once incoming connection is detected, that class /// calls accept(), which returns a new socket dedicated to handling that /// specific connection. That socket is represented by this class. class ConnectionSocket : public CommandSocket { public: /// @brief Default constructor /// /// This constructor is used in methods that call accept on existing /// sockets. accept() returns a socket descriptor. Hence only one /// parameter here. /// /// @param sockfd socket descriptor ConnectionSocket(int sockfd); /// @brief Method used to handle incoming data /// /// This method calls isc::config::CommandMgr::commandReader method. virtual void receiveHandler(); /// @brief Closes socket. /// /// This method closes the socket, prints appropriate log message and /// unregisters callback from @ref isc::dhcp::IfaceMgr. virtual void close(); }; }; }; #endif kea-1.1.0/src/lib/config/module_spec.h0000664000175000017500000002113612772017075014461 00000000000000// Copyright (C) 2010-2015 Internet Systems Consortium. // // 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 MODULE_SPEC_H #define MODULE_SPEC_H 1 #include #include namespace isc { namespace config { /// /// A standard ModuleSpec exception that is thrown when a /// specification is not in the correct form. /// class ModuleSpecError : public isc::Exception { public: ModuleSpecError(const char* file, size_t line, const char* what = "Module specification is invalid") : isc::Exception(file, line, what) {} }; /// /// The \c ModuleSpec class holds a data specification. /// Each module should have a .spec file containing the specification /// for configuration and commands for that module. /// This class holds that specification, and provides a function to /// validate a set of data, to see whether it conforms to the given /// specification /// /// The form of the specification is described in doc/ (TODO) /// class ModuleSpec { public: ModuleSpec() {}; /// Create a \c ModuleSpec instance with the given data as /// the specification /// \param e The Element containing the data specification /// \param check If false, the module specification in the file /// is not checked to be of the correct form. explicit ModuleSpec(isc::data::ConstElementPtr e, const bool check = true) throw(ModuleSpecError); /// Returns the commands part of the specification as an /// ElementPtr, returns an empty ElementPtr if there is none /// \return ElementPtr Shared pointer to the commands /// part of the specification isc::data::ConstElementPtr getCommandsSpec() const; /// Returns the configuration part of the specification as an /// ElementPtr /// \return ElementPtr Shared pointer to the configuration /// part of the specification isc::data::ConstElementPtr getConfigSpec() const; /// Returns the statistics part of the specification as an /// ElementPtr /// \return ElementPtr Shared pointer to the statistics /// part of the specification isc::data::ConstElementPtr getStatisticsSpec() const; /// Returns the full module specification as an ElementPtr /// \return ElementPtr Shared pointer to the specification isc::data::ConstElementPtr getFullSpec() const { return module_specification; } /// Returns the module name as specified by the specification const std::string getModuleName() const; /// Returns the module description as specified by the specification /// returns an empty string if there is no description const std::string getModuleDescription() const; // returns true if the given element conforms to this data // configuration specification /// Validates the given configuration data for this specification. /// \param data The base \c Element of the data to check /// \param full If true, all non-optional configuration parameters /// must be specified. /// \return true if the data conforms to the specification, /// false otherwise. bool validateConfig(isc::data::ConstElementPtr data, const bool full = false) const; // returns true if the given element conforms to this data // statistics specification /// Validates the given statistics data for this specification. /// \param data The base \c Element of the data to check /// \param full If true, all non-optional statistics parameters /// must be specified. /// \return true if the data conforms to the specification, /// false otherwise. bool validateStatistics(isc::data::ConstElementPtr data, const bool full = false) const; /// Validates the arguments for the given command /// /// This checks the command and argument against the /// specification in the module's .spec file. /// /// A command is considered valid if: /// - it is known (the 'command' string must have an entry in /// the specification) /// - the args is a MapElement /// - args contains all mandatory arguments /// - args does not contain unknown arguments /// - all arguments in args match their specification /// If all of these are true, this function returns \c true /// If not, this method returns \c false /// /// Example usage: /// \code /// ElementPtr errors = Element::createList(); /// if (module_specification_.validateCommand(cmd_str, /// arg, /// errors)) { /// std::cout << "Command is valid" << std::endl; /// } else { /// std::cout << "Command is invalid: " << std::endl; /// BOOST_FOREACH(ConstElementPtr error, /// errors->listValue()) { /// std::cout << error->stringValue() << std::endl; /// } /// } /// \endcode /// /// \param command The command to validate the arguments for /// \param args A dict containing the command parameters /// \param errors An ElementPtr pointing to a ListElement. Any /// errors that are found are added as /// StringElements to this list /// \return true if the command is known and the parameters are correct /// false otherwise bool validateCommand(const std::string& command, isc::data::ConstElementPtr args, isc::data::ElementPtr errors) const; /// errors must be of type ListElement bool validateConfig(isc::data::ConstElementPtr data, const bool full, isc::data::ElementPtr errors) const; /// errors must be of type ListElement bool validateStatistics(isc::data::ConstElementPtr data, const bool full, isc::data::ElementPtr errors) const; private: bool validateItem(isc::data::ConstElementPtr spec, isc::data::ConstElementPtr data, const bool full, isc::data::ElementPtr errors) const; bool validateSpec(isc::data::ConstElementPtr spec, isc::data::ConstElementPtr data, const bool full, isc::data::ElementPtr errors) const; bool validateSpecList(isc::data::ConstElementPtr spec, isc::data::ConstElementPtr data, const bool full, isc::data::ElementPtr errors) const; isc::data::ConstElementPtr module_specification; }; /// Creates a \c ModuleSpec instance from the contents /// of the file given by file_name. /// If check is true, and the module specification is not of /// the correct form, a ModuleSpecError is thrown. If the file /// could not be parse, a ParseError is thrown. /// \param file_name The file to be opened and parsed /// \param check If true, the module specification in the file /// is checked to be of the correct form ModuleSpec moduleSpecFromFile(const std::string& file_name, const bool check = true) throw(isc::data::JSONError, ModuleSpecError); /// Creates a \c ModuleSpec instance from the given input /// stream that contains the contents of a .spec file. /// If check is true, and the module specification is not of /// the correct form, a ModuleSpecError is thrown. If the /// file could not be parsed, a ParseError is thrown. /// \param in The std::istream containing the .spec file data /// \param check If true, the module specification is checked /// to be of the correct form ModuleSpec moduleSpecFromFile(std::ifstream& in, const bool check = true) throw(isc::data::JSONError, ModuleSpecError); } } #endif // _DATA_DEF_H // Local Variables: // mode: c++ // End: kea-1.1.0/src/lib/config/command_mgr.h0000664000175000017500000001617612772017075014455 00000000000000// Copyright (C) 2015 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 COMMAND_MGR_H #define COMMAND_MGR_H #include #include #include #include #include #include #include namespace isc { namespace config { /// @brief CommandMgr exception indicating that the handler specified is not valid class InvalidCommandHandler : public Exception { public: InvalidCommandHandler(const char* file, size_t line, const char* what) : isc::Exception(file, line, what) { }; }; /// @brief CommandMgr exception indicating that the command name is not valid class InvalidCommandName : public Exception { public: InvalidCommandName(const char* file, size_t line, const char* what) : isc::Exception(file, line, what) { }; }; /// @brief Commands Manager, responsible for processing external commands /// /// Commands Manager is a generic interface for handling external commands. /// Commands can be received over control sockets. Currently unix socket is /// supported, but additional type (udp, tcp, https etc.) may be added later. /// The commands and responses are sent in JSON format. /// See http://kea.isc.org/wiki/StatsDesign for details. /// /// In general, the command has the following format: /// { /// "command": "statistic-get", /// "arguments": { /// "name": "received-packets" /// } /// } /// /// And the response is: /// /// { /// "result": 0, /// "observations": { /// "received-packets": [ [ 1234, "2015-04-15 12:34:45.123" ] ] /// } /// } /// /// CommandsMgr does not implement the commands (except one, "list-commands") /// itself, but rather provides an interface (see @ref registerCommand, /// @ref deregisterCommand, @ref processCommand) for other components to use /// it. The @ref CommandHandler type is specified in a way to easily use /// existing command handlers in DHCPv4 and DHCPv6 components. class CommandMgr : public boost::noncopyable { public: /// @brief Defines command handler type /// /// Command handlers are expected to use this format. /// @param name name of the commands /// @param params parameters specific to the command /// @return response (created with createAnswer()) typedef boost::function CommandHandler; /// @brief CommandMgr is a singleton class. This method returns reference /// to its sole instance. /// /// @return the only existing instance of the manager static CommandMgr& instance(); /// @brief Opens control socket with paramters specified in socket_info /// /// Currently supported types are: /// - unix (required parameters: socket-type: unix, socket-name:/unix/path) /// /// This method will close previously open command socket (if exists). /// /// @throw CommandSocketError if socket creation fails. /// @throw SocketError if command socket is already open. /// /// @param socket_info describes control socket parameters /// @return object representing a socket CommandSocketPtr openCommandSocket(const isc::data::ConstElementPtr& socket_info); /// @brief Shuts down any open control sockets void closeCommandSocket(); /// @brief Registers specified command handler for a given command /// /// @param cmd name of the command to be handled /// @param handler pointer to the method that will handle the command void registerCommand(const std::string& cmd, CommandHandler handler); /// @brief Deregisters specified command handler /// /// @param cmd name of the command that's no longer handled void deregisterCommand(const std::string& cmd); /// @brief Triggers command processing /// /// This method processes specified command. The command is specified using /// a single Element. See @ref CommandMgr for description of its syntax. /// Typically, this method is called internally, when there's a new data /// received over control socket. However, in some cases (e.g. signal received) /// it may be called by external code explicitly. Hence this method is public. isc::data::ConstElementPtr processCommand(const isc::data::ConstElementPtr& cmd); /// @brief Reads data from a socket, parses as JSON command and processes it /// /// This method is used to handle traffic on connected socket. This callback /// is installed by the @c isc::config::UnixCommandSocket::receiveHandler /// (located in the src/lib/config/command_socket_factory.cc) /// once the incoming connection is accepted. If end-of-file is detected, this /// method will close the socket and will uninstall itself from /// @ref isc::dhcp::IfaceMgr. /// /// @param sockfd socket descriptor of a connected socket static void commandReader(int sockfd); /// @brief Auxiliary method that removes all installed commands. /// /// The only unwipeable method is list-commands, which is internally /// handled at all times. void deregisterAll(); /// @brief Adds an information about opened connection socket /// /// @param conn Connection socket to be stored void addConnection(const CommandSocketPtr& conn); /// @brief Closes connection with a specific socket descriptor /// /// @param fd socket descriptor /// @return true if closed successfully, false if not found bool closeConnection(int fd); /// @brief Returns control socket descriptor /// /// This method should be used only in tests. int getControlSocketFD() const { return (socket_->getFD()); } private: /// @brief Private constructor /// /// Registers internal 'list-commands' command. CommandMgr(); /// @brief 'list-commands' command handler /// /// This method implements command 'list-commands'. It returns a list of all /// currently supported commands. /// @param name name of the command (should always be 'list-commands') /// @param params additional parameters (ignored) /// @return structure that includes all currently supported commands isc::data::ConstElementPtr listCommandsHandler(const std::string& name, const isc::data::ConstElementPtr& params); typedef std::map HandlerContainer; /// @brief Container for command handlers HandlerContainer handlers_; /// @brief Control socket structure /// /// This is the socket that accepts incoming connections. There can be at /// most one (if command channel is configured). CommandSocketPtr socket_; /// @brief Sockets for open connections /// /// These are the sockets that are dedicated to handle a specific connection. /// Their number is equal to number of current control connections. std::list connections_; }; }; // end of isc::config namespace }; // end of isc namespace #endif kea-1.1.0/src/lib/config/config_data.h0000664000175000017500000001200612772017075014414 00000000000000// Copyright (C) 2009-2015 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 CONFIG_DATA_H #define CONFIG_DATA_H 1 #include #include #include #include namespace isc { namespace config { /// This exception is thrown when the caller is trying to access /// data that doesn't exist (i.e. with an identifier that does not /// point to anything defined in the .spec file) class DataNotFoundError : public isc::Exception { public: DataNotFoundError(const char* file, size_t line, const char* what) : isc::Exception(file, line, what) {} }; class ConfigData { public: /// Constructs a ConfigData option with no specification and an /// empty configuration. ConfigData() { _config = isc::data::Element::createMap(); }; /// Constructs a ConfigData option with the given specification /// and an empty configuration. /// \param module_spec A ModuleSpec for the relevant module ConfigData(const ModuleSpec& module_spec) : _module_spec(module_spec) { _config = isc::data::Element::createMap(); } virtual ~ConfigData() {}; /// Returns the value currently set for the given identifier /// If no value is set, the default value (as specified by the /// .spec file) is returned. If there is no value and no default, /// an empty ElementPtr is returned. /// Raises a DataNotFoundError if the identifier is bad. /// \param identifier The identifier pointing to the configuration /// value that is to be returned isc::data::ConstElementPtr getValue(const std::string& identifier) const; /// Returns the default value for the given identifier. /// /// \exception DataNotFoundError if the given identifier does not /// exist, or if the given value has no specified default /// /// \param identifier The identifier pointing to the configuration /// value for which the default is to be returned /// \return ElementPtr containing the default value isc::data::ConstElementPtr getDefaultValue(const std::string& identifier) const; /// Returns the value currently set for the given identifier /// If no value is set, the default value (as specified by the /// .spec file) is returned. If there is no value and no default, /// an empty ElementPtr is returned. /// Raises a DataNotFoundError if the identifier is bad. /// \param is_default will be set to true if the value is taken /// from the specifications item_default setting, /// false otherwise /// \param identifier The identifier pointing to the configuration /// value that is to be returned isc::data::ConstElementPtr getValue(bool& is_default, const std::string& identifier) const; /// Returns the ModuleSpec associated with this ConfigData object const ModuleSpec& getModuleSpec() const { return (_module_spec); } /// Set the ModuleSpec associated with this ConfigData object void setModuleSpec(ModuleSpec module_spec) { _module_spec = module_spec; }; /// Set the local configuration (i.e. all non-default values) /// \param config An ElementPtr pointing to a MapElement containing /// *all* non-default configuration values. Existing values /// will be removed. void setLocalConfig(isc::data::ElementPtr config) { _config = config; } /// Returns the local (i.e. non-default) configuration. /// \return An ElementPtr pointing to a MapElement containing all /// non-default configuration options. isc::data::ElementPtr getLocalConfig() { return (_config); } /// Returns a list of all possible configuration options as specified /// by the ModuleSpec. /// \param identifier If given, show the items at the given identifier /// (iff that is also a MapElement) /// \param recurse If true, child MapElements will be traversed to /// add their identifiers to the result list /// \return An ElementPtr pointing to a ListElement containing /// StringElements that specify the identifiers at the given /// location (or all possible identifiers if identifier=="" /// and recurse==false) isc::data::ConstElementPtr getItemList(const std::string& identifier = "", bool recurse = false) const; /// \brief Returns a map of the top-level configuration items, as /// currently set or their defaults. /// /// \return An ElementPtr pointing to a MapElement containing /// the top-level configuration items isc::data::ConstElementPtr getFullConfig() const; private: isc::data::ElementPtr _config; ModuleSpec _module_spec; }; } } #endif // Local Variables: // mode: c++ // End: kea-1.1.0/src/lib/config/tests/0000775000175000017500000000000012772742662013237 500000000000000kea-1.1.0/src/lib/config/tests/Makefile.in0000664000175000017500000012356512772742615015236 00000000000000# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ TESTS = $(am__EXEEXT_1) @HAVE_GTEST_TRUE@am__append_1 = run_unittests noinst_PROGRAMS = $(am__EXEEXT_2) subdir = src/lib/config/tests DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(srcdir)/data_def_unittests_config.h.in $(top_srcdir)/depcomp ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4macros/ax_boost_for_kea.m4 \ $(top_srcdir)/m4macros/ax_isc_rpath.m4 \ $(top_srcdir)/m4macros/libtool.m4 \ $(top_srcdir)/m4macros/ltoptions.m4 \ $(top_srcdir)/m4macros/ltsugar.m4 \ $(top_srcdir)/m4macros/ltversion.m4 \ $(top_srcdir)/m4macros/lt~obsolete.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = data_def_unittests_config.h CONFIG_CLEAN_VPATH_FILES = @HAVE_GTEST_TRUE@am__EXEEXT_1 = run_unittests$(EXEEXT) am__EXEEXT_2 = $(am__EXEEXT_1) PROGRAMS = $(noinst_PROGRAMS) am__run_unittests_SOURCES_DIST = module_spec_unittests.cc \ command_socket_factory_unittests.cc config_data_unittests.cc \ run_unittests.cc command_mgr_unittests.cc @HAVE_GTEST_TRUE@am_run_unittests_OBJECTS = run_unittests-module_spec_unittests.$(OBJEXT) \ @HAVE_GTEST_TRUE@ run_unittests-command_socket_factory_unittests.$(OBJEXT) \ @HAVE_GTEST_TRUE@ run_unittests-config_data_unittests.$(OBJEXT) \ @HAVE_GTEST_TRUE@ run_unittests-run_unittests.$(OBJEXT) \ @HAVE_GTEST_TRUE@ run_unittests-command_mgr_unittests.$(OBJEXT) run_unittests_OBJECTS = $(am_run_unittests_OBJECTS) am__DEPENDENCIES_1 = @HAVE_GTEST_TRUE@run_unittests_DEPENDENCIES = $(top_builddir)/src/lib/config/libkea-cfgclient.la \ @HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/dhcp/libkea-dhcp++.la \ @HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/asiolink/libkea-asiolink.la \ @HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/cc/libkea-cc.la \ @HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/dns/libkea-dns++.la \ @HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/cryptolink/libkea-cryptolink.la \ @HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/log/libkea-log.la \ @HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/util/threads/libkea-threads.la \ @HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/util/unittests/libutil_unittests.la \ @HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/util/libkea-util.la \ @HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/exceptions/libkea-exceptions.la \ @HAVE_GTEST_TRUE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ @HAVE_GTEST_TRUE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = run_unittests_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(AM_CXXFLAGS) $(CXXFLAGS) $(run_unittests_LDFLAGS) $(LDFLAGS) \ -o $@ AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CXXFLAGS) $(CXXFLAGS) AM_V_CXX = $(am__v_CXX_@AM_V@) am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@) am__v_CXX_0 = @echo " CXX " $@; am__v_CXX_1 = CXXLD = $(CXX) CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CXXLD = $(am__v_CXXLD_@AM_V@) am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@) am__v_CXXLD_0 = @echo " CXXLD " $@; am__v_CXXLD_1 = SOURCES = $(run_unittests_SOURCES) DIST_SOURCES = $(am__run_unittests_SOURCES_DIST) RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ install-exec-recursive install-html-recursive \ install-info-recursive install-pdf-recursive \ install-ps-recursive install-recursive installcheck-recursive \ installdirs-recursive pdf-recursive ps-recursive \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ distdir am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags am__tty_colors_dummy = \ mgn= red= grn= lgn= blu= brg= std=; \ am__color_tests=no am__tty_colors = { \ $(am__tty_colors_dummy); \ if test "X$(AM_COLOR_TESTS)" = Xno; then \ am__color_tests=no; \ elif test "X$(AM_COLOR_TESTS)" = Xalways; then \ am__color_tests=yes; \ elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \ am__color_tests=yes; \ fi; \ if test $$am__color_tests = yes; then \ red=''; \ grn=''; \ lgn=''; \ blu=''; \ mgn=''; \ brg=''; \ std=''; \ fi; \ } DIST_SUBDIRS = $(SUBDIRS) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ASCIIDOC = @ASCIIDOC@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BOOST_INCLUDES = @BOOST_INCLUDES@ BOOST_LIBS = @BOOST_LIBS@ BOTAN_TOOL = @BOTAN_TOOL@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CQL_CPPFLAGS = @CQL_CPPFLAGS@ CQL_LIBS = @CQL_LIBS@ CRYPTO_CFLAGS = @CRYPTO_CFLAGS@ CRYPTO_INCLUDES = @CRYPTO_INCLUDES@ CRYPTO_LDFLAGS = @CRYPTO_LDFLAGS@ CRYPTO_LIBS = @CRYPTO_LIBS@ CRYPTO_PACKAGE = @CRYPTO_PACKAGE@ CRYPTO_RPATH = @CRYPTO_RPATH@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DBLATEX = @DBLATEX@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DISTCHECK_BOOST_CONFIGURE_FLAG = @DISTCHECK_BOOST_CONFIGURE_FLAG@ DISTCHECK_CRYPTO_CONFIGURE_FLAG = @DISTCHECK_CRYPTO_CONFIGURE_FLAG@ DISTCHECK_GTEST_CONFIGURE_FLAG = @DISTCHECK_GTEST_CONFIGURE_FLAG@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ ELINKS = @ELINKS@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GENHTML = @GENHTML@ GREP = @GREP@ GTEST_CONFIG = @GTEST_CONFIG@ GTEST_INCLUDES = @GTEST_INCLUDES@ GTEST_LDADD = @GTEST_LDADD@ GTEST_LDFLAGS = @GTEST_LDFLAGS@ GTEST_SOURCE = @GTEST_SOURCE@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ KEA_CXXFLAGS = @KEA_CXXFLAGS@ LCOV = @LCOV@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LEXLIB = @LEXLIB@ LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LOG4CPLUS_INCLUDES = @LOG4CPLUS_INCLUDES@ LOG4CPLUS_LIBS = @LOG4CPLUS_LIBS@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ MYSQL_LIBS = @MYSQL_LIBS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PERL = @PERL@ PGSQL_CPPFLAGS = @PGSQL_CPPFLAGS@ PGSQL_LIBS = @PGSQL_LIBS@ PKG_CONFIG = @PKG_CONFIG@ PLANTUML = @PLANTUML@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SEP = @SEP@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ USE_LCOV = @USE_LCOV@ VALGRIND = @VALGRIND@ VERSION = @VERSION@ WARNING_GCC_44_STRICT_ALIASING_CFLAG = @WARNING_GCC_44_STRICT_ALIASING_CFLAG@ XSLTPROC = @XSLTPROC@ YACC = @YACC@ YFLAGS = @YFLAGS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ SUBDIRS = testdata . AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib \ $(BOOST_INCLUDES) \ -DTEST_DATA_BUILDDIR=\"$(abs_top_builddir)/src/lib/config/tests\" AM_CXXFLAGS = $(KEA_CXXFLAGS) @USE_STATIC_LINK_TRUE@AM_LDFLAGS = -static CLEANFILES = *.gcno *.gcda TESTS_ENVIRONMENT = \ $(LIBTOOL) --mode=execute $(VALGRIND_COMMAND) @HAVE_GTEST_TRUE@run_unittests_SOURCES = module_spec_unittests.cc \ @HAVE_GTEST_TRUE@ command_socket_factory_unittests.cc \ @HAVE_GTEST_TRUE@ config_data_unittests.cc run_unittests.cc \ @HAVE_GTEST_TRUE@ command_mgr_unittests.cc @HAVE_GTEST_TRUE@run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES) @HAVE_GTEST_TRUE@run_unittests_LDFLAGS = $(AM_LDFLAGS) $(CRYPTO_LDFLAGS) $(GTEST_LDFLAGS) @HAVE_GTEST_TRUE@run_unittests_LDADD = $(top_builddir)/src/lib/config/libkea-cfgclient.la \ @HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/dhcp/libkea-dhcp++.la \ @HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/asiolink/libkea-asiolink.la \ @HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/cc/libkea-cc.la \ @HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/dns/libkea-dns++.la \ @HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/cryptolink/libkea-cryptolink.la \ @HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/log/libkea-log.la \ @HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/util/threads/libkea-threads.la \ @HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/util/unittests/libutil_unittests.la \ @HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/util/libkea-util.la \ @HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/exceptions/libkea-exceptions.la \ @HAVE_GTEST_TRUE@ $(LOG4CPLUS_LIBS) $(CRYPTO_LIBS) \ @HAVE_GTEST_TRUE@ $(BOOST_LIBS) $(GTEST_LDADD) all: all-recursive .SUFFIXES: .SUFFIXES: .cc .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/lib/config/tests/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign src/lib/config/tests/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): data_def_unittests_config.h: $(top_builddir)/config.status $(srcdir)/data_def_unittests_config.h.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ clean-noinstPROGRAMS: @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list run_unittests$(EXEEXT): $(run_unittests_OBJECTS) $(run_unittests_DEPENDENCIES) $(EXTRA_run_unittests_DEPENDENCIES) @rm -f run_unittests$(EXEEXT) $(AM_V_CXXLD)$(run_unittests_LINK) $(run_unittests_OBJECTS) $(run_unittests_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-command_mgr_unittests.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-command_socket_factory_unittests.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-config_data_unittests.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-module_spec_unittests.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-run_unittests.Po@am__quote@ .cc.o: @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $< .cc.obj: @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .cc.lo: @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $< run_unittests-module_spec_unittests.o: module_spec_unittests.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-module_spec_unittests.o -MD -MP -MF $(DEPDIR)/run_unittests-module_spec_unittests.Tpo -c -o run_unittests-module_spec_unittests.o `test -f 'module_spec_unittests.cc' || echo '$(srcdir)/'`module_spec_unittests.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-module_spec_unittests.Tpo $(DEPDIR)/run_unittests-module_spec_unittests.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='module_spec_unittests.cc' object='run_unittests-module_spec_unittests.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-module_spec_unittests.o `test -f 'module_spec_unittests.cc' || echo '$(srcdir)/'`module_spec_unittests.cc run_unittests-module_spec_unittests.obj: module_spec_unittests.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-module_spec_unittests.obj -MD -MP -MF $(DEPDIR)/run_unittests-module_spec_unittests.Tpo -c -o run_unittests-module_spec_unittests.obj `if test -f 'module_spec_unittests.cc'; then $(CYGPATH_W) 'module_spec_unittests.cc'; else $(CYGPATH_W) '$(srcdir)/module_spec_unittests.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-module_spec_unittests.Tpo $(DEPDIR)/run_unittests-module_spec_unittests.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='module_spec_unittests.cc' object='run_unittests-module_spec_unittests.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-module_spec_unittests.obj `if test -f 'module_spec_unittests.cc'; then $(CYGPATH_W) 'module_spec_unittests.cc'; else $(CYGPATH_W) '$(srcdir)/module_spec_unittests.cc'; fi` run_unittests-command_socket_factory_unittests.o: command_socket_factory_unittests.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-command_socket_factory_unittests.o -MD -MP -MF $(DEPDIR)/run_unittests-command_socket_factory_unittests.Tpo -c -o run_unittests-command_socket_factory_unittests.o `test -f 'command_socket_factory_unittests.cc' || echo '$(srcdir)/'`command_socket_factory_unittests.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-command_socket_factory_unittests.Tpo $(DEPDIR)/run_unittests-command_socket_factory_unittests.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='command_socket_factory_unittests.cc' object='run_unittests-command_socket_factory_unittests.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-command_socket_factory_unittests.o `test -f 'command_socket_factory_unittests.cc' || echo '$(srcdir)/'`command_socket_factory_unittests.cc run_unittests-command_socket_factory_unittests.obj: command_socket_factory_unittests.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-command_socket_factory_unittests.obj -MD -MP -MF $(DEPDIR)/run_unittests-command_socket_factory_unittests.Tpo -c -o run_unittests-command_socket_factory_unittests.obj `if test -f 'command_socket_factory_unittests.cc'; then $(CYGPATH_W) 'command_socket_factory_unittests.cc'; else $(CYGPATH_W) '$(srcdir)/command_socket_factory_unittests.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-command_socket_factory_unittests.Tpo $(DEPDIR)/run_unittests-command_socket_factory_unittests.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='command_socket_factory_unittests.cc' object='run_unittests-command_socket_factory_unittests.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-command_socket_factory_unittests.obj `if test -f 'command_socket_factory_unittests.cc'; then $(CYGPATH_W) 'command_socket_factory_unittests.cc'; else $(CYGPATH_W) '$(srcdir)/command_socket_factory_unittests.cc'; fi` run_unittests-config_data_unittests.o: config_data_unittests.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-config_data_unittests.o -MD -MP -MF $(DEPDIR)/run_unittests-config_data_unittests.Tpo -c -o run_unittests-config_data_unittests.o `test -f 'config_data_unittests.cc' || echo '$(srcdir)/'`config_data_unittests.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-config_data_unittests.Tpo $(DEPDIR)/run_unittests-config_data_unittests.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='config_data_unittests.cc' object='run_unittests-config_data_unittests.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-config_data_unittests.o `test -f 'config_data_unittests.cc' || echo '$(srcdir)/'`config_data_unittests.cc run_unittests-config_data_unittests.obj: config_data_unittests.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-config_data_unittests.obj -MD -MP -MF $(DEPDIR)/run_unittests-config_data_unittests.Tpo -c -o run_unittests-config_data_unittests.obj `if test -f 'config_data_unittests.cc'; then $(CYGPATH_W) 'config_data_unittests.cc'; else $(CYGPATH_W) '$(srcdir)/config_data_unittests.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-config_data_unittests.Tpo $(DEPDIR)/run_unittests-config_data_unittests.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='config_data_unittests.cc' object='run_unittests-config_data_unittests.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-config_data_unittests.obj `if test -f 'config_data_unittests.cc'; then $(CYGPATH_W) 'config_data_unittests.cc'; else $(CYGPATH_W) '$(srcdir)/config_data_unittests.cc'; fi` run_unittests-run_unittests.o: run_unittests.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-run_unittests.o -MD -MP -MF $(DEPDIR)/run_unittests-run_unittests.Tpo -c -o run_unittests-run_unittests.o `test -f 'run_unittests.cc' || echo '$(srcdir)/'`run_unittests.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-run_unittests.Tpo $(DEPDIR)/run_unittests-run_unittests.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='run_unittests.cc' object='run_unittests-run_unittests.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-run_unittests.o `test -f 'run_unittests.cc' || echo '$(srcdir)/'`run_unittests.cc run_unittests-run_unittests.obj: run_unittests.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-run_unittests.obj -MD -MP -MF $(DEPDIR)/run_unittests-run_unittests.Tpo -c -o run_unittests-run_unittests.obj `if test -f 'run_unittests.cc'; then $(CYGPATH_W) 'run_unittests.cc'; else $(CYGPATH_W) '$(srcdir)/run_unittests.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-run_unittests.Tpo $(DEPDIR)/run_unittests-run_unittests.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='run_unittests.cc' object='run_unittests-run_unittests.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-run_unittests.obj `if test -f 'run_unittests.cc'; then $(CYGPATH_W) 'run_unittests.cc'; else $(CYGPATH_W) '$(srcdir)/run_unittests.cc'; fi` run_unittests-command_mgr_unittests.o: command_mgr_unittests.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-command_mgr_unittests.o -MD -MP -MF $(DEPDIR)/run_unittests-command_mgr_unittests.Tpo -c -o run_unittests-command_mgr_unittests.o `test -f 'command_mgr_unittests.cc' || echo '$(srcdir)/'`command_mgr_unittests.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-command_mgr_unittests.Tpo $(DEPDIR)/run_unittests-command_mgr_unittests.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='command_mgr_unittests.cc' object='run_unittests-command_mgr_unittests.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-command_mgr_unittests.o `test -f 'command_mgr_unittests.cc' || echo '$(srcdir)/'`command_mgr_unittests.cc run_unittests-command_mgr_unittests.obj: command_mgr_unittests.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-command_mgr_unittests.obj -MD -MP -MF $(DEPDIR)/run_unittests-command_mgr_unittests.Tpo -c -o run_unittests-command_mgr_unittests.obj `if test -f 'command_mgr_unittests.cc'; then $(CYGPATH_W) 'command_mgr_unittests.cc'; else $(CYGPATH_W) '$(srcdir)/command_mgr_unittests.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-command_mgr_unittests.Tpo $(DEPDIR)/run_unittests-command_mgr_unittests.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='command_mgr_unittests.cc' object='run_unittests-command_mgr_unittests.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-command_mgr_unittests.obj `if test -f 'command_mgr_unittests.cc'; then $(CYGPATH_W) 'command_mgr_unittests.cc'; else $(CYGPATH_W) '$(srcdir)/command_mgr_unittests.cc'; fi` mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs # This directory's subdirectories are mostly independent; you can cd # into them and run 'make' without going through this Makefile. # To change the values of 'make' variables: instead of editing Makefiles, # (1) if the variable is set in 'config.status', edit 'config.status' # (which will cause the Makefiles to be regenerated when you run 'make'); # (2) otherwise, pass the desired values on the 'make' command line. $(am__recursive_targets): @fail=; \ if $(am__make_keepgoing); then \ failcom='fail=yes'; \ else \ failcom='exit 1'; \ fi; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-recursive CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-recursive cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags check-TESTS: $(TESTS) @failed=0; all=0; xfail=0; xpass=0; skip=0; \ srcdir=$(srcdir); export srcdir; \ list=' $(TESTS) '; \ $(am__tty_colors); \ if test -n "$$list"; then \ for tst in $$list; do \ if test -f ./$$tst; then dir=./; \ elif test -f $$tst; then dir=; \ else dir="$(srcdir)/"; fi; \ if $(TESTS_ENVIRONMENT) $${dir}$$tst $(AM_TESTS_FD_REDIRECT); then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xpass=`expr $$xpass + 1`; \ failed=`expr $$failed + 1`; \ col=$$red; res=XPASS; \ ;; \ *) \ col=$$grn; res=PASS; \ ;; \ esac; \ elif test $$? -ne 77; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xfail=`expr $$xfail + 1`; \ col=$$lgn; res=XFAIL; \ ;; \ *) \ failed=`expr $$failed + 1`; \ col=$$red; res=FAIL; \ ;; \ esac; \ else \ skip=`expr $$skip + 1`; \ col=$$blu; res=SKIP; \ fi; \ echo "$${col}$$res$${std}: $$tst"; \ done; \ if test "$$all" -eq 1; then \ tests="test"; \ All=""; \ else \ tests="tests"; \ All="All "; \ fi; \ if test "$$failed" -eq 0; then \ if test "$$xfail" -eq 0; then \ banner="$$All$$all $$tests passed"; \ else \ if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ fi; \ else \ if test "$$xpass" -eq 0; then \ banner="$$failed of $$all $$tests failed"; \ else \ if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ fi; \ fi; \ dashes="$$banner"; \ skipped=""; \ if test "$$skip" -ne 0; then \ if test "$$skip" -eq 1; then \ skipped="($$skip test was not run)"; \ else \ skipped="($$skip tests were not run)"; \ fi; \ test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$skipped"; \ fi; \ report=""; \ if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ report="Please report to $(PACKAGE_BUGREPORT)"; \ test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$report"; \ fi; \ dashes=`echo "$$dashes" | sed s/./=/g`; \ if test "$$failed" -eq 0; then \ col="$$grn"; \ else \ col="$$red"; \ fi; \ echo "$${col}$$dashes$${std}"; \ echo "$${col}$$banner$${std}"; \ test -z "$$skipped" || echo "$${col}$$skipped$${std}"; \ test -z "$$report" || echo "$${col}$$report$${std}"; \ echo "$${col}$$dashes$${std}"; \ test "$$failed" -eq 0; \ else :; fi distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done check-am: all-am $(MAKE) $(AM_MAKEFLAGS) check-TESTS check: check-recursive all-am: Makefile $(PROGRAMS) installdirs: installdirs-recursive installdirs-am: install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-recursive clean-am: clean-generic clean-libtool clean-noinstPROGRAMS \ mostlyclean-am distclean: distclean-recursive -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: .MAKE: $(am__recursive_targets) check-am install-am install-strip .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ check-TESTS check-am clean clean-generic clean-libtool \ clean-noinstPROGRAMS cscopelist-am ctags ctags-am distclean \ distclean-compile distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ installdirs-am maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: kea-1.1.0/src/lib/config/tests/data_def_unittests_config.h.in0000664000175000017500000000050212772017075021121 00000000000000// Copyright (C) 2009-2015 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/. #define TEST_DATA_PATH "@abs_srcdir@/testdata" kea-1.1.0/src/lib/config/tests/module_spec_unittests.cc0000664000175000017500000003707412772017075020113 00000000000000// Copyright (C) 2009-2015 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 #include #include #include #include using namespace isc::data; using namespace isc::config; std::string specfile(const std::string& name) { return (std::string(TEST_DATA_PATH) + "/" + name); } void moduleSpecError(const std::string& file, const std::string& error1, const std::string& error2 = "", const std::string& error3 = "") { EXPECT_THROW(moduleSpecFromFile(specfile(file)), ModuleSpecError); try { ModuleSpec dd = moduleSpecFromFile(specfile(file)); } catch (const ModuleSpecError& dde) { std::string ddew = dde.what(); EXPECT_EQ(error1 + error2 + error3, ddew); } } TEST(ModuleSpec, ReadingSpecfiles) { // Tests whether we can open specfiles and if we get the // right parse errors ModuleSpec dd = moduleSpecFromFile(specfile("spec1.spec")); EXPECT_EQ(dd.getFullSpec()->get("module_name") ->stringValue(), "Spec1"); dd = moduleSpecFromFile(specfile("spec2.spec")); EXPECT_EQ(dd.getFullSpec()->get("config_data")->size(), 6); moduleSpecError("doesnotexist", "Error opening ", specfile("doesnotexist"), ": No such file or directory"); dd = moduleSpecFromFile(specfile("spec2.spec")); EXPECT_EQ("[ { \"command_args\": [ { \"item_default\": \"\", \"item_name\": \"message\", \"item_optional\": false, \"item_type\": \"string\" } ], \"command_description\": \"Print the given message to stdout\", \"command_name\": \"print_message\" }, { \"command_args\": [ ], \"command_description\": \"Shut down Kea\", \"command_name\": \"shutdown\" } ]", dd.getCommandsSpec()->str()); EXPECT_EQ("[ { \"item_default\": \"1970-01-01T00:00:00Z\", \"item_description\": \"A dummy date time\", \"item_format\": \"date-time\", \"item_name\": \"dummy_time\", \"item_optional\": false, \"item_title\": \"Dummy Time\", \"item_type\": \"string\" } ]", dd.getStatisticsSpec()->str()); EXPECT_EQ("Spec2", dd.getModuleName()); EXPECT_EQ("", dd.getModuleDescription()); dd = moduleSpecFromFile(specfile("spec25.spec")); EXPECT_EQ("Spec25", dd.getModuleName()); EXPECT_EQ("Just an empty module", dd.getModuleDescription()); EXPECT_THROW(moduleSpecFromFile(specfile("spec26.spec")), ModuleSpecError); EXPECT_THROW(moduleSpecFromFile(specfile("spec34.spec")), ModuleSpecError); EXPECT_THROW(moduleSpecFromFile(specfile("spec35.spec")), ModuleSpecError); EXPECT_THROW(moduleSpecFromFile(specfile("spec36.spec")), ModuleSpecError); EXPECT_THROW(moduleSpecFromFile(specfile("spec37.spec")), ModuleSpecError); EXPECT_THROW(moduleSpecFromFile(specfile("spec38.spec")), ModuleSpecError); std::ifstream file; file.open(specfile("spec1.spec").c_str()); dd = moduleSpecFromFile(file); EXPECT_EQ(dd.getFullSpec()->get("module_name") ->stringValue(), "Spec1"); EXPECT_TRUE(isNull(dd.getCommandsSpec())); EXPECT_TRUE(isNull(dd.getStatisticsSpec())); std::ifstream file2; file2.open(specfile("spec8.spec").c_str()); EXPECT_THROW(moduleSpecFromFile(file2), ModuleSpecError); } TEST(ModuleSpec, SpecfileItems) { moduleSpecError("spec3.spec", "item_name missing in { \"item_default\": 1, \"item_optional\": false, \"item_type\": \"integer\" }"); moduleSpecError("spec4.spec", "item_type missing in { \"item_default\": 1, \"item_name\": \"item1\", \"item_optional\": false }"); moduleSpecError("spec5.spec", "item_optional missing in { \"item_default\": 1, \"item_name\": \"item1\", \"item_type\": \"integer\" }"); moduleSpecError("spec6.spec", "item_default missing in { \"item_name\": \"item1\", \"item_optional\": false, \"item_type\": \"integer\" }"); moduleSpecError("spec9.spec", "item_default not of type integer"); moduleSpecError("spec10.spec", "item_default not of type real"); moduleSpecError("spec11.spec", "item_default not of type boolean"); moduleSpecError("spec12.spec", "item_default not of type string"); moduleSpecError("spec13.spec", "item_default not of type list"); moduleSpecError("spec14.spec", "item_default not of type map"); moduleSpecError("spec15.spec", "badname is not a valid type name"); EXPECT_NO_THROW(moduleSpecFromFile(specfile("spec40.spec"))); } TEST(ModuleSpec, SpecfileConfigData) { moduleSpecError("spec7.spec", "module_name missing in { }"); moduleSpecError("spec8.spec", "No module_spec in specification"); moduleSpecError("spec16.spec", "config_data is not a list of elements"); moduleSpecError("spec21.spec", "commands is not a list of elements"); } TEST(ModuleSpec, SpecfileStatistics) { moduleSpecError("spec36.spec", "item_default not valid type of item_format"); moduleSpecError("spec37.spec", "statistics is not a list of elements"); moduleSpecError("spec38.spec", "item_default not valid type of item_format"); } TEST(ModuleSpec, SpecfileCommands) { moduleSpecError("spec17.spec", "command_name missing in { \"command_args\": [ { \"item_default\": \"\", \"item_name\": \"message\", \"item_optional\": false, \"item_type\": \"string\" } ], \"command_description\": \"Print the given message to stdout\" }"); moduleSpecError("spec18.spec", "command_args missing in { \"command_description\": \"Print the given message to stdout\", \"command_name\": \"print_message\" }"); moduleSpecError("spec19.spec", "command_args not of type list"); moduleSpecError("spec20.spec", "somethingbad is not a valid type name"); } bool dataTest(const ModuleSpec& dd, const std::string& data_file_name) { std::ifstream data_file; data_file.open(specfile(data_file_name).c_str()); ConstElementPtr data = Element::fromJSON(data_file, data_file_name); data_file.close(); return (dd.validateConfig(data)); } bool statisticsTest(const ModuleSpec& dd, const std::string& data_file_name) { std::ifstream data_file; data_file.open(specfile(data_file_name).c_str()); ConstElementPtr data = Element::fromJSON(data_file, data_file_name); data_file.close(); return (dd.validateStatistics(data)); } bool dataTestWithErrors(const ModuleSpec& dd, const std::string& data_file_name, ElementPtr errors) { std::ifstream data_file; data_file.open(specfile(data_file_name).c_str()); ConstElementPtr data = Element::fromJSON(data_file, data_file_name); data_file.close(); return (dd.validateConfig(data, true, errors)); } bool statisticsTestWithErrors(const ModuleSpec& dd, const std::string& data_file_name, ElementPtr errors) { std::ifstream data_file; data_file.open(specfile(data_file_name).c_str()); ConstElementPtr data = Element::fromJSON(data_file, data_file_name); data_file.close(); return (dd.validateStatistics(data, true, errors)); } TEST(ModuleSpec, DataValidation) { ModuleSpec dd = moduleSpecFromFile(specfile("spec22.spec")); EXPECT_TRUE(dataTest(dd, "data22_1.data")); EXPECT_FALSE(dataTest(dd, "data22_2.data")); EXPECT_FALSE(dataTest(dd, "data22_3.data")); EXPECT_FALSE(dataTest(dd, "data22_4.data")); EXPECT_FALSE(dataTest(dd, "data22_5.data")); EXPECT_TRUE(dataTest(dd, "data22_6.data")); EXPECT_TRUE(dataTest(dd, "data22_7.data")); EXPECT_FALSE(dataTest(dd, "data22_8.data")); EXPECT_FALSE(dataTest(dd, "data22_9.data")); // Test if "version" is allowed in config data // (same data as 22_7, but added "version") EXPECT_TRUE(dataTest(dd, "data22_10.data")); ElementPtr errors = Element::createList(); EXPECT_FALSE(dataTestWithErrors(dd, "data22_8.data", errors)); EXPECT_EQ("[ \"Type mismatch\" ]", errors->str()); errors = Element::createList(); EXPECT_FALSE(dataTestWithErrors(dd, "data22_9.data", errors)); EXPECT_EQ("[ \"Unknown item value_does_not_exist\" ]", errors->str()); } TEST(ModuleSpec, StatisticsValidation) { ModuleSpec dd = moduleSpecFromFile(specfile("spec33.spec")); EXPECT_TRUE(statisticsTest(dd, "data33_1.data")); EXPECT_FALSE(statisticsTest(dd, "data33_2.data")); ElementPtr errors = Element::createList(); EXPECT_FALSE(statisticsTestWithErrors(dd, "data33_2.data", errors)); EXPECT_EQ("[ \"Format mismatch\", \"Format mismatch\", \"Format mismatch\" ]", errors->str()); dd = moduleSpecFromFile(specfile("spec41.spec")); EXPECT_TRUE(statisticsTest(dd, "data41_1.data")); EXPECT_FALSE(statisticsTest(dd, "data41_2.data")); errors = Element::createList(); EXPECT_FALSE(statisticsTestWithErrors(dd, "data41_2.data", errors)); EXPECT_EQ("[ \"Type mismatch\" ]", errors->str()); } TEST(ModuleSpec, CommandValidation) { ModuleSpec dd = moduleSpecFromFile(specfile("spec2.spec")); ConstElementPtr arg = Element::fromJSON("{}"); ElementPtr errors = Element::createList(); EXPECT_TRUE(dd.validateCommand("shutdown", arg, errors)); EXPECT_EQ(errors->size(), 0); errors = Element::createList(); EXPECT_FALSE(dd.validateCommand("unknowncommand", arg, errors)); EXPECT_EQ(errors->size(), 1); EXPECT_EQ(errors->get(0)->stringValue(), "Unknown command unknowncommand"); errors = Element::createList(); EXPECT_FALSE(dd.validateCommand("print_message", arg, errors)); EXPECT_EQ(errors->size(), 1); EXPECT_EQ(errors->get(0)->stringValue(), "Non-optional value missing"); errors = Element::createList(); arg = Element::fromJSON("{ \"message\": \"Hello\" }"); EXPECT_TRUE(dd.validateCommand("print_message", arg, errors)); EXPECT_EQ(errors->size(), 0); errors = Element::createList(); arg = Element::fromJSON("{ \"message\": \"Hello\", \"unknown_second_arg\": 1 }"); EXPECT_FALSE(dd.validateCommand("print_message", arg, errors)); EXPECT_EQ(errors->size(), 1); EXPECT_EQ(errors->get(0)->stringValue(), "Unknown item unknown_second_arg"); errors = Element::createList(); arg = Element::fromJSON("{ \"message\": 1 }"); EXPECT_FALSE(dd.validateCommand("print_message", arg, errors)); EXPECT_EQ(errors->size(), 1); EXPECT_EQ(errors->get(0)->stringValue(), "Type mismatch"); } TEST(ModuleSpec, NamedSetValidation) { ModuleSpec dd = moduleSpecFromFile(specfile("spec32.spec")); ElementPtr errors = Element::createList(); EXPECT_TRUE(dataTestWithErrors(dd, "data32_1.data", errors)); EXPECT_FALSE(dataTest(dd, "data32_2.data")); EXPECT_FALSE(dataTest(dd, "data32_3.data")); } TEST(ModuleSpec, CheckFormat) { const std::string json_begin = "{ \"module_spec\": { \"module_name\": \"Foo\", \"statistics\": [ { \"item_name\": \"dummy_time\", \"item_type\": \"string\", \"item_optional\": true, \"item_title\": \"Dummy Time\", \"item_description\": \"A dummy date time\""; const std::string json_end = " } ] } }"; std::string item_default; std::string item_format; std::vector specs; ConstElementPtr el; specs.clear(); item_default = "\"item_default\": \"2011-05-27T19:42:57Z\","; item_format = "\"item_format\": \"date-time\""; specs.push_back("," + item_default + item_format); item_default = "\"item_default\": \"2011-05-27\","; item_format = "\"item_format\": \"date\""; specs.push_back("," + item_default + item_format); item_default = "\"item_default\": \"19:42:57\","; item_format = "\"item_format\": \"time\""; specs.push_back("," + item_default + item_format); item_format = "\"item_format\": \"date-time\""; specs.push_back("," + item_format); item_default = ""; item_format = "\"item_format\": \"date\""; specs.push_back("," + item_format); // cppcheck-suppress redundantAssignment item_default = ""; item_format = "\"item_format\": \"time\""; specs.push_back("," + item_format); // cppcheck-suppress redundantAssignment item_default = "\"item_default\": \"a\""; specs.push_back("," + item_default); item_default = "\"item_default\": \"b\""; specs.push_back("," + item_default); item_default = "\"item_default\": \"c\""; specs.push_back("," + item_default); item_format = "\"item_format\": \"dummy\""; specs.push_back("," + item_format); specs.push_back(""); BOOST_FOREACH(std::string s, specs) { el = Element::fromJSON(json_begin + s + json_end)->get("module_spec"); EXPECT_NO_THROW(ModuleSpec(el, true)); } specs.clear(); item_default = "\"item_default\": \"2011-05-27T19:42:57Z\","; item_format = "\"item_format\": \"dummy\""; specs.push_back("," + item_default + item_format); item_default = "\"item_default\": \"2011-05-27\","; item_format = "\"item_format\": \"dummy\""; specs.push_back("," + item_default + item_format); item_default = "\"item_default\": \"19:42:57Z\","; item_format = "\"item_format\": \"dummy\""; specs.push_back("," + item_default + item_format); item_default = "\"item_default\": \"2011-13-99T99:99:99Z\","; item_format = "\"item_format\": \"date-time\""; specs.push_back("," + item_default + item_format); item_default = "\"item_default\": \"2011-13-99\","; item_format = "\"item_format\": \"date\""; specs.push_back("," + item_default + item_format); item_default = "\"item_default\": \"99:99:99Z\","; item_format = "\"item_format\": \"time\""; specs.push_back("," + item_default + item_format); item_default = "\"item_default\": \"1\","; item_format = "\"item_format\": \"date-time\""; specs.push_back("," + item_default + item_format); item_default = "\"item_default\": \"1\","; item_format = "\"item_format\": \"date\""; specs.push_back("," + item_default + item_format); item_default = "\"item_default\": \"1\","; item_format = "\"item_format\": \"time\""; specs.push_back("," + item_default + item_format); item_default = "\"item_default\": \"\","; item_format = "\"item_format\": \"date-time\""; specs.push_back("," + item_default + item_format); item_default = "\"item_default\": \"\","; item_format = "\"item_format\": \"date\""; specs.push_back("," + item_default + item_format); item_default = "\"item_default\": \"\","; item_format = "\"item_format\": \"time\""; specs.push_back("," + item_default + item_format); // wrong date-time-type format not ending with "Z" item_default = "\"item_default\": \"2011-05-27T19:42:57\","; item_format = "\"item_format\": \"date-time\""; specs.push_back("," + item_default + item_format); // wrong date-type format ending with "T" item_default = "\"item_default\": \"2011-05-27T\","; item_format = "\"item_format\": \"date\""; specs.push_back("," + item_default + item_format); // wrong time-type format ending with "Z" item_default = "\"item_default\": \"19:42:57Z\","; item_format = "\"item_format\": \"time\""; specs.push_back("," + item_default + item_format); BOOST_FOREACH(std::string s, specs) { el = Element::fromJSON(json_begin + s + json_end)->get("module_spec"); EXPECT_THROW(ModuleSpec(el, true), ModuleSpecError); } } kea-1.1.0/src/lib/config/tests/config_data_unittests.cc0000664000175000017500000001553112772017075020044 00000000000000 // Copyright (C) 2009-2015 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 #include #include #include using namespace isc::data; using namespace isc::config; ConfigData setupSpec2() { ModuleSpec spec2 = moduleSpecFromFile(std::string(TEST_DATA_PATH) + "/spec22.spec"); return (ConfigData(spec2)); } TEST(ConfigData, Creation) { ConfigData cd = setupSpec2(); EXPECT_TRUE(true); } TEST(ConfigData, getValue) { ModuleSpec spec22 = moduleSpecFromFile(std::string(TEST_DATA_PATH) + "/spec22.spec"); ConfigData cd = ConfigData(spec22); //std::cout << "[XX] SPEC2: " << cd.getModuleSpec().getFullSpec() << std::endl; bool is_default; //ElementPtr value = cd.getValue(is_default, "item1"); EXPECT_EQ(9, cd.getValue("value1")->intValue()); EXPECT_EQ(9, cd.getValue(is_default, "value1")->intValue()); EXPECT_TRUE(is_default); EXPECT_EQ(9.9, cd.getValue("value2")->doubleValue()); EXPECT_EQ(9.9, cd.getValue(is_default, "value2")->doubleValue()); EXPECT_TRUE(is_default); EXPECT_FALSE(cd.getValue("value3")->boolValue()); EXPECT_FALSE(cd.getValue(is_default, "value3")->boolValue()); EXPECT_TRUE(is_default); EXPECT_EQ("default_string", cd.getValue("value4")->stringValue()); EXPECT_EQ("default_string", cd.getValue(is_default, "value4")->stringValue()); EXPECT_TRUE(is_default); EXPECT_EQ("a", cd.getValue("value5")->get(0)->stringValue()); EXPECT_EQ("a", cd.getValue(is_default, "value5")->get(0)->stringValue()); EXPECT_TRUE(is_default); EXPECT_EQ("b", cd.getValue("value5")->get(1)->stringValue()); EXPECT_EQ("b", cd.getValue(is_default, "value5")->get(1)->stringValue()); EXPECT_EQ("b", cd.getValue(is_default, "value5/")->get(1)->stringValue()); EXPECT_TRUE(is_default); EXPECT_EQ("{ }", cd.getValue("value6")->str()); EXPECT_EQ("{ }", cd.getValue(is_default, "value6")->str()); EXPECT_EQ("{ }", cd.getValue(is_default, "value6/")->str()); EXPECT_TRUE(is_default); EXPECT_EQ("[ ]", cd.getValue("value8")->str()); EXPECT_EQ("[ ]", cd.getDefaultValue("value8")->str()); EXPECT_EQ("empty", cd.getValue("value8/a")->stringValue()); EXPECT_THROW(cd.getValue("")->str(), DataNotFoundError); EXPECT_THROW(cd.getValue("/")->str(), DataNotFoundError); EXPECT_THROW(cd.getValue("no_such_item")->str(), DataNotFoundError); EXPECT_THROW(cd.getValue("value6/a")->str(), DataNotFoundError); EXPECT_THROW(cd.getValue("value6/no_such_item")->str(), DataNotFoundError); EXPECT_THROW(cd.getValue("value8/b")->str(), DataNotFoundError); ModuleSpec spec1 = moduleSpecFromFile(std::string(TEST_DATA_PATH) + "/spec1.spec"); ConfigData cd1 = ConfigData(spec1); EXPECT_THROW(cd1.getValue("anything")->str(), DataNotFoundError); } TEST(ConfigData, getDefaultValue) { ModuleSpec spec31 = moduleSpecFromFile(std::string(TEST_DATA_PATH) + "/spec31.spec"); ConfigData cd = ConfigData(spec31); EXPECT_EQ("[ ]", cd.getDefaultValue("first_list_items")->str()); EXPECT_EQ("\"foo\"", cd.getDefaultValue("first_list_items/foo")->str()); EXPECT_EQ("{ }", cd.getDefaultValue("first_list_items/second_list_items/map_element")->str()); EXPECT_EQ("[ ]", cd.getDefaultValue("first_list_items/second_list_items/map_element/list1")->str()); EXPECT_EQ("1", cd.getDefaultValue("first_list_items/second_list_items/map_element/list1/number")->str()); EXPECT_THROW(cd.getDefaultValue("doesnotexist")->str(), DataNotFoundError); EXPECT_THROW(cd.getDefaultValue("first_list_items/second_list_items/map_element/list1/doesnotexist")->str(), DataNotFoundError); } TEST(ConfigData, setLocalConfig) { ModuleSpec spec2 = moduleSpecFromFile(std::string(TEST_DATA_PATH) + "/spec2.spec"); ConfigData cd = ConfigData(spec2); bool is_default; ElementPtr my_config = Element::fromJSON("{ \"item1\": 2 }"); ElementPtr my_config2 = Element::fromJSON("{ \"item6\": { \"value1\": \"a\" } }"); EXPECT_EQ("{ }", cd.getValue("item6")->str()); cd.setLocalConfig(my_config); EXPECT_EQ(2, cd.getValue(is_default, "item1")->intValue()); EXPECT_FALSE(is_default); EXPECT_EQ("{ }", cd.getValue("item6")->str()); EXPECT_EQ(1.1, cd.getValue(is_default, "item2")->doubleValue()); EXPECT_TRUE(is_default); cd.setLocalConfig(my_config2); EXPECT_EQ("{ \"value1\": \"a\" }", cd.getValue("item6")->str()); } TEST(ConfigData, getLocalConfig) { ModuleSpec spec2 = moduleSpecFromFile(std::string(TEST_DATA_PATH) + "/spec2.spec"); ConfigData cd = ConfigData(spec2); EXPECT_EQ("{ }", cd.getLocalConfig()->str()); ElementPtr my_config = Element::fromJSON("{ \"item1\": 2 }"); cd.setLocalConfig(my_config); EXPECT_EQ("{ \"item1\": 2 }", cd.getLocalConfig()->str()); ElementPtr my_config2 = Element::fromJSON("{ \"item6\": { \"value1\": \"a\" } }"); cd.setLocalConfig(my_config2); EXPECT_EQ("{ \"item6\": { \"value1\": \"a\" } }", cd.getLocalConfig()->str()); } TEST(ConfigData, getItemList) { ModuleSpec spec2 = moduleSpecFromFile(std::string(TEST_DATA_PATH) + "/spec2.spec"); ConfigData cd = ConfigData(spec2); EXPECT_EQ("[ \"item1\", \"item2\", \"item3\", \"item4\", \"item5\", \"item6\" ]", cd.getItemList()->str()); EXPECT_EQ("[ \"item1\", \"item2\", \"item3\", \"item4\", \"item5\", \"item6/value1\", \"item6/value2\" ]", cd.getItemList("", true)->str()); EXPECT_EQ("[ \"item6/value1\", \"item6/value2\" ]", cd.getItemList("item6")->str()); } TEST(ConfigData, getFullConfig) { ModuleSpec spec2 = moduleSpecFromFile(std::string(TEST_DATA_PATH) + "/spec2.spec"); ConfigData cd = ConfigData(spec2); EXPECT_EQ("{ \"item1\": 1, \"item2\": 1.1, \"item3\": true, \"item4\": \"test\", \"item5\": [ \"a\", \"b\" ], \"item6\": { } }", cd.getFullConfig()->str()); ElementPtr my_config = Element::fromJSON("{ \"item1\": 2 }"); cd.setLocalConfig(my_config); EXPECT_EQ("{ \"item1\": 2, \"item2\": 1.1, \"item3\": true, \"item4\": \"test\", \"item5\": [ \"a\", \"b\" ], \"item6\": { } }", cd.getFullConfig()->str()); ElementPtr my_config2 = Element::fromJSON("{ \"item6\": { \"value1\": \"a\" } }"); cd.setLocalConfig(my_config2); EXPECT_EQ("{ \"item1\": 1, \"item2\": 1.1, \"item3\": true, \"item4\": \"test\", \"item5\": [ \"a\", \"b\" ], \"item6\": { \"value1\": \"a\" } }", cd.getFullConfig()->str()); ElementPtr my_config3 = Element::fromJSON("{ \"item6\": { \"value2\": 123 } }"); cd.setLocalConfig(my_config3); EXPECT_EQ("{ \"item1\": 1, \"item2\": 1.1, \"item3\": true, \"item4\": \"test\", \"item5\": [ \"a\", \"b\" ], \"item6\": { \"value2\": 123 } }", cd.getFullConfig()->str()); } kea-1.1.0/src/lib/config/tests/Makefile.am0000664000175000017500000000327312772017075015211 00000000000000SUBDIRS = testdata . AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib AM_CPPFLAGS += $(BOOST_INCLUDES) AM_CPPFLAGS += -DTEST_DATA_BUILDDIR=\"$(abs_top_builddir)/src/lib/config/tests\" AM_CXXFLAGS = $(KEA_CXXFLAGS) if USE_STATIC_LINK AM_LDFLAGS = -static endif CLEANFILES = *.gcno *.gcda TESTS_ENVIRONMENT = \ $(LIBTOOL) --mode=execute $(VALGRIND_COMMAND) TESTS = if HAVE_GTEST TESTS += run_unittests run_unittests_SOURCES = module_spec_unittests.cc run_unittests_SOURCES += command_socket_factory_unittests.cc run_unittests_SOURCES += config_data_unittests.cc run_unittests.cc run_unittests_SOURCES += command_mgr_unittests.cc run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES) run_unittests_LDFLAGS = $(AM_LDFLAGS) $(CRYPTO_LDFLAGS) $(GTEST_LDFLAGS) run_unittests_LDADD = $(top_builddir)/src/lib/config/libkea-cfgclient.la run_unittests_LDADD += $(top_builddir)/src/lib/dhcp/libkea-dhcp++.la run_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libkea-asiolink.la run_unittests_LDADD += $(top_builddir)/src/lib/cc/libkea-cc.la run_unittests_LDADD += $(top_builddir)/src/lib/dns/libkea-dns++.la run_unittests_LDADD += $(top_builddir)/src/lib/cryptolink/libkea-cryptolink.la run_unittests_LDADD += $(top_builddir)/src/lib/log/libkea-log.la run_unittests_LDADD += $(top_builddir)/src/lib/util/threads/libkea-threads.la run_unittests_LDADD += $(top_builddir)/src/lib/util/unittests/libutil_unittests.la run_unittests_LDADD += $(top_builddir)/src/lib/util/libkea-util.la run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libkea-exceptions.la run_unittests_LDADD += $(LOG4CPLUS_LIBS) $(CRYPTO_LIBS) run_unittests_LDADD += $(BOOST_LIBS) $(GTEST_LDADD) endif noinst_PROGRAMS = $(TESTS) kea-1.1.0/src/lib/config/tests/command_mgr_unittests.cc0000664000175000017500000001730612772017075020073 00000000000000// Copyright (C) 2015 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 #include #include using namespace isc::data; using namespace isc::config; using namespace std; // Test class for Command Manager class CommandMgrTest : public ::testing::Test { public: /// Default constructor CommandMgrTest() { handler_name = ""; handler_params = ElementPtr(); handler_called = false; CommandMgr::instance().deregisterAll(); CommandMgr::instance().closeCommandSocket(); } /// Default destructor ~CommandMgrTest() { CommandMgr::instance().deregisterAll(); CommandMgr::instance().closeCommandSocket(); } /// @brief A simple command handler that always returns an eror static ConstElementPtr my_handler(const std::string& name, const ConstElementPtr& params) { handler_name = name; handler_params = params; handler_called = true; return (createAnswer(123, "test error message")); } /// @brief Name of the command (used in my_handler) static std::string handler_name; /// @brief Parameters passed to the handler (used in my_handler) static ConstElementPtr handler_params; /// @brief Indicates whether my_handler was called static bool handler_called; }; /// Name passed to the handler (used in my_handler) std::string CommandMgrTest::handler_name(""); /// Parameters passed to the handler (used in my_handler) ConstElementPtr CommandMgrTest::handler_params; /// Indicates whether my_handler was called bool CommandMgrTest::handler_called(false); // Test checks whether the internal command 'list-commands' // is working properly. TEST_F(CommandMgrTest, listCommandsEmpty) { ConstElementPtr command = createCommand("list-commands"); ConstElementPtr answer; EXPECT_NO_THROW(answer = CommandMgr::instance().processCommand(command)); ASSERT_TRUE(answer); EXPECT_EQ("{ \"arguments\": [ \"list-commands\" ], \"result\": 0 }", answer->str()); } // Test checks whether calling a bogus command is handled properly. TEST_F(CommandMgrTest, bogusCommand) { ConstElementPtr command = createCommand("no-such-command"); ConstElementPtr answer; EXPECT_NO_THROW(answer = CommandMgr::instance().processCommand(command)); // Make sure the status code is non-zero ASSERT_TRUE(answer); int status_code; parseAnswer(status_code, answer); EXPECT_EQ(CONTROL_RESULT_ERROR, status_code); } // Test checks whether handlers installation is sanitized. In particular, // whether NULL handler and attempt to install handlers for the same // command twice are rejected. TEST_F(CommandMgrTest, handlerInstall) { // Check that it's not allowed to install NULL pointer instead of a real // command. EXPECT_THROW(CommandMgr::instance().registerCommand("my-command", NULL), InvalidCommandHandler); // This registration should succeed. EXPECT_NO_THROW(CommandMgr::instance().registerCommand("my-command", my_handler)); // Check that it's not possible to install handlers for the same // command twice. EXPECT_THROW(CommandMgr::instance().registerCommand("my-command", my_handler), InvalidCommandName); } // Test checks whether the internal list-commands command is working // correctly. Also, checks installation and deinstallation of other // command handlers. TEST_F(CommandMgrTest, listCommands) { // Let's install two custom commands. EXPECT_NO_THROW(CommandMgr::instance().registerCommand("make-a-coffee", my_handler)); EXPECT_NO_THROW(CommandMgr::instance().registerCommand("do-the-dishes", my_handler)); // And then run 'list-commands' ConstElementPtr list_all = createCommand("list-commands"); ConstElementPtr answer; // Now check that the command is returned by list-commands EXPECT_NO_THROW(answer = CommandMgr::instance().processCommand(list_all)); ASSERT_TRUE(answer); EXPECT_EQ("{ \"arguments\": [ \"do-the-dishes\", \"list-commands\", " "\"make-a-coffee\" ], \"result\": 0 }", answer->str()); // Now unregister one command EXPECT_NO_THROW(CommandMgr::instance().deregisterCommand("do-the-dishes")); // Now check that the command is returned by list-commands EXPECT_NO_THROW(answer = CommandMgr::instance().processCommand(list_all)); ASSERT_TRUE(answer); EXPECT_EQ("{ \"arguments\": [ \"list-commands\", " "\"make-a-coffee\" ], \"result\": 0 }", answer->str()); // Now test deregistration. It should work the first time. EXPECT_NO_THROW(CommandMgr::instance().deregisterCommand("make-a-coffee")); // Second time should throw an exception as the handler is no longer there. EXPECT_THROW(CommandMgr::instance().deregisterCommand("make-a-coffee"), InvalidCommandName); // You can't unistall list-commands as it's the internal handler. // It always must be there. EXPECT_THROW(CommandMgr::instance().deregisterCommand("list-commands"), InvalidCommandName); // Attempt to register a handler for existing command should fail. EXPECT_THROW(CommandMgr::instance().registerCommand("list-commands", my_handler), InvalidCommandName); } // Test checks whether deregisterAll method uninstalls all handlers, // except list-commands. TEST_F(CommandMgrTest, deregisterAll) { // Install a couple handlers. EXPECT_NO_THROW(CommandMgr::instance().registerCommand("my-command1", my_handler)); EXPECT_NO_THROW(CommandMgr::instance().registerCommand("my-command2", my_handler)); EXPECT_NO_THROW(CommandMgr::instance().deregisterAll()); ConstElementPtr answer; EXPECT_NO_THROW(answer = CommandMgr::instance() .processCommand(createCommand("list-commands"))); ASSERT_TRUE(answer); EXPECT_EQ("{ \"arguments\": [ \"list-commands\" ], \"result\": 0 }", answer->str()); } // Test checks whether a command handler can be installed and then // runs through processCommand to check that it's indeed called. TEST_F(CommandMgrTest, processCommand) { // Install my handler EXPECT_NO_THROW(CommandMgr::instance().registerCommand("my-command", my_handler)); // Now tell CommandMgr to process a command 'my-command' with the // specified parameter. ElementPtr my_params = Element::fromJSON("[ \"just\", \"some\", \"data\" ]"); ConstElementPtr command = createCommand("my-command", my_params); ConstElementPtr answer; EXPECT_NO_THROW(answer = CommandMgr::instance().processCommand(command)); // There should be an answer. ASSERT_TRUE(answer); // my_handler remembers all passed parameters and returns status code of 123. ConstElementPtr answer_arg; int status_code; // Check that the returned status code is correct. EXPECT_NO_THROW(answer_arg = parseAnswer(status_code, answer)); EXPECT_EQ(123, status_code); // Check that the parameters passed are correct. EXPECT_EQ(true, handler_called); EXPECT_EQ("my-command", handler_name); ASSERT_TRUE(handler_params); EXPECT_EQ("[ \"just\", \"some\", \"data\" ]", handler_params->str()); } kea-1.1.0/src/lib/config/tests/command_socket_factory_unittests.cc0000664000175000017500000000614412772017075022323 00000000000000// Copyright (C) 2015 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 #include #include #include #include #include #include using namespace isc::config; using namespace isc::data; // Test class for Command Manager class CommandSocketFactoryTest : public ::testing::Test { public: /// Default constructor CommandSocketFactoryTest() :SOCKET_NAME(getSocketPath()) { // Remove any stale socket files static_cast(remove(SOCKET_NAME.c_str())); } /// Default destructor ~CommandSocketFactoryTest() { // Remove any stale socket files static_cast(remove(SOCKET_NAME.c_str())); } /// @brief Returns socket path (using either hardcoded path or env variable) /// @return path to the unix socket std::string getSocketPath() { std::string socket_path; const char* env = getenv("KEA_SOCKET_TEST_DIR"); if (env) { socket_path = std::string(env) + "/test-socket"; } else { socket_path = std::string(TEST_DATA_BUILDDIR) + "/test-socket"; } return (socket_path); } std::string SOCKET_NAME; }; // This test verifies that a Unix socket can be opened properly and that input // parameters (socket-type and socket-name) are verified. TEST_F(CommandSocketFactoryTest, unixCreate) { // Null pointer is obviously a bad idea. EXPECT_THROW(CommandSocketFactory::create(ConstElementPtr()), isc::config::BadSocketInfo); // So is passing no parameters. ElementPtr socket_info = Element::createMap(); EXPECT_THROW(CommandSocketFactory::create(socket_info), isc::config::BadSocketInfo); // We don't support ipx sockets socket_info->set("socket-type", Element::create("ipx")); EXPECT_THROW(CommandSocketFactory::create(socket_info), isc::config::BadSocketInfo); socket_info->set("socket-type", Element::create("unix")); EXPECT_THROW(CommandSocketFactory::create(socket_info), isc::config::BadSocketInfo); socket_info->set("socket-name", Element::create(SOCKET_NAME)); CommandSocketPtr sock; EXPECT_NO_THROW(sock = CommandSocketFactory::create(socket_info)); ASSERT_TRUE(sock); EXPECT_NE(-1, sock->getFD()); // It should be possible to close the socket. EXPECT_NO_THROW(sock->close()); } // This test checks that when unix path is too long, the socket cannot be opened. TEST_F(CommandSocketFactoryTest, unixCreateTooLong) { ElementPtr socket_info = Element::fromJSON("{ \"socket-type\": \"unix\"," "\"socket-name\": \"/tmp/toolongtoolongtoolongtoolongtoolongtoolong" "toolongtoolongtoolongtoolongtoolongtoolongtoolongtoolongtoolong" "\" }"); EXPECT_THROW(CommandSocketFactory::create(socket_info), SocketError); } kea-1.1.0/src/lib/config/tests/testdata/0000775000175000017500000000000012772742662015050 500000000000000kea-1.1.0/src/lib/config/tests/testdata/Makefile.in0000664000175000017500000003376312772742615017047 00000000000000# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = src/lib/config/tests/testdata DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4macros/ax_boost_for_kea.m4 \ $(top_srcdir)/m4macros/ax_isc_rpath.m4 \ $(top_srcdir)/m4macros/libtool.m4 \ $(top_srcdir)/m4macros/ltoptions.m4 \ $(top_srcdir)/m4macros/ltsugar.m4 \ $(top_srcdir)/m4macros/ltversion.m4 \ $(top_srcdir)/m4macros/lt~obsolete.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ASCIIDOC = @ASCIIDOC@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BOOST_INCLUDES = @BOOST_INCLUDES@ BOOST_LIBS = @BOOST_LIBS@ BOTAN_TOOL = @BOTAN_TOOL@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CQL_CPPFLAGS = @CQL_CPPFLAGS@ CQL_LIBS = @CQL_LIBS@ CRYPTO_CFLAGS = @CRYPTO_CFLAGS@ CRYPTO_INCLUDES = @CRYPTO_INCLUDES@ CRYPTO_LDFLAGS = @CRYPTO_LDFLAGS@ CRYPTO_LIBS = @CRYPTO_LIBS@ CRYPTO_PACKAGE = @CRYPTO_PACKAGE@ CRYPTO_RPATH = @CRYPTO_RPATH@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DBLATEX = @DBLATEX@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DISTCHECK_BOOST_CONFIGURE_FLAG = @DISTCHECK_BOOST_CONFIGURE_FLAG@ DISTCHECK_CRYPTO_CONFIGURE_FLAG = @DISTCHECK_CRYPTO_CONFIGURE_FLAG@ DISTCHECK_GTEST_CONFIGURE_FLAG = @DISTCHECK_GTEST_CONFIGURE_FLAG@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ ELINKS = @ELINKS@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GENHTML = @GENHTML@ GREP = @GREP@ GTEST_CONFIG = @GTEST_CONFIG@ GTEST_INCLUDES = @GTEST_INCLUDES@ GTEST_LDADD = @GTEST_LDADD@ GTEST_LDFLAGS = @GTEST_LDFLAGS@ GTEST_SOURCE = @GTEST_SOURCE@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ KEA_CXXFLAGS = @KEA_CXXFLAGS@ LCOV = @LCOV@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LEXLIB = @LEXLIB@ LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LOG4CPLUS_INCLUDES = @LOG4CPLUS_INCLUDES@ LOG4CPLUS_LIBS = @LOG4CPLUS_LIBS@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ MYSQL_LIBS = @MYSQL_LIBS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PERL = @PERL@ PGSQL_CPPFLAGS = @PGSQL_CPPFLAGS@ PGSQL_LIBS = @PGSQL_LIBS@ PKG_CONFIG = @PKG_CONFIG@ PLANTUML = @PLANTUML@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SEP = @SEP@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ USE_LCOV = @USE_LCOV@ VALGRIND = @VALGRIND@ VERSION = @VERSION@ WARNING_GCC_44_STRICT_ALIASING_CFLAG = @WARNING_GCC_44_STRICT_ALIASING_CFLAG@ XSLTPROC = @XSLTPROC@ YACC = @YACC@ YFLAGS = @YFLAGS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ EXTRA_DIST = data22_1.data data22_2.data data22_3.data data22_4.data \ data22_5.data data22_6.data data22_7.data data22_8.data \ data22_9.data data22_10.data data32_1.data data32_2.data \ data32_3.data data33_1.data data33_2.data data41_1.data \ data41_2.data spec1.spec spec2.spec spec3.spec spec4.spec \ spec5.spec spec6.spec spec7.spec spec8.spec spec9.spec \ spec10.spec spec11.spec spec12.spec spec13.spec spec14.spec \ spec15.spec spec16.spec spec17.spec spec18.spec spec19.spec \ spec20.spec spec21.spec spec22.spec spec23.spec spec24.spec \ spec25.spec spec26.spec spec27.spec spec28.spec spec29.spec \ spec30.spec spec31.spec spec32.spec spec33.spec spec34.spec \ spec35.spec spec36.spec spec37.spec spec38.spec spec39.spec \ spec40.spec spec41.spec spec42.spec all: all-am .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/lib/config/tests/testdata/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign src/lib/config/tests/testdata/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags-am uninstall uninstall-am # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: kea-1.1.0/src/lib/config/tests/testdata/spec37.spec0000664000175000017500000000011512772017075016736 00000000000000{ "module_spec": { "module_name": "Spec37", "statistics": 8 } } kea-1.1.0/src/lib/config/tests/testdata/spec36.spec0000664000175000017500000000053012772017075016736 00000000000000{ "module_spec": { "module_name": "Spec36", "statistics": [ { "item_name": "dummy_str", "item_type": "string", "item_optional": false, "item_default": "Dummy", "item_title": "Dummy String", "item_description": "A dummy string", "item_format": "dummy" } ] } } kea-1.1.0/src/lib/config/tests/testdata/spec11.spec0000664000175000017500000000032312772017075016727 00000000000000{ "module_spec": { "module_name": "Spec2", "config_data": [ { "item_name": "item1", "item_type": "boolean", "item_optional": false, "item_default": 1 } ] } } kea-1.1.0/src/lib/config/tests/testdata/spec40.spec0000664000175000017500000000066412772017075016741 00000000000000{ "module_spec": { "module_name": "Spec40", "config_data": [ { "item_name": "item1", "item_type": "any", "item_optional": false, "item_default": "asdf" }, { "item_name": "item2", "item_type": "any", "item_optional": true }, { "item_name": "item3", "item_type": "any", "item_optional": true, "item_default": null } ] } } kea-1.1.0/src/lib/config/tests/testdata/spec38.spec0000664000175000017500000000054212772017075016743 00000000000000{ "module_spec": { "module_name": "Spec38", "statistics": [ { "item_name": "dummy_datetime", "item_type": "string", "item_optional": false, "item_default": "11", "item_title": "Dummy DateTime", "item_description": "A dummy datetime", "item_format": "date-time" } ] } } kea-1.1.0/src/lib/config/tests/testdata/data33_1.data0000664000175000017500000000024612772017075017115 00000000000000{ "dummy_str": "Dummy String", "dummy_int": 118, "dummy_datetime": "2011-05-27T19:42:57Z", "dummy_date": "2011-05-27", "dummy_time": "19:42:57" } kea-1.1.0/src/lib/config/tests/testdata/spec28.spec0000664000175000017500000000011512772017075016736 00000000000000{ "module_spec": { "module_name": "Spec28", 'commands': [ ] } } kea-1.1.0/src/lib/config/tests/testdata/spec25.spec0000664000175000017500000000015212772017075016734 00000000000000{ "module_spec": { "module_name": "Spec25", "module_description": "Just an empty module" } } kea-1.1.0/src/lib/config/tests/testdata/spec24.spec0000664000175000017500000000054212772017075016736 00000000000000{ "module_spec": { "module_name": "Spec24", "config_data": [ { "item_name": "item", "item_type": "list", "item_optional": true, "list_item_spec": { "item_name": "list_element", "item_type": "string", "item_optional": false, "item_default": "" } } ] } } kea-1.1.0/src/lib/config/tests/testdata/spec2.spec0000664000175000017500000000407512772017075016657 00000000000000{ "module_spec": { "module_name": "Spec2", "config_data": [ { "item_name": "item1", "item_type": "integer", "item_optional": false, "item_default": 1 }, { "item_name": "item2", "item_type": "real", "item_optional": false, "item_default": 1.1 }, { "item_name": "item3", "item_type": "boolean", "item_optional": false, "item_default": true }, { "item_name": "item4", "item_type": "string", "item_optional": false, "item_default": "test" }, { "item_name": "item5", "item_type": "list", "item_optional": false, "item_default": [ "a", "b" ], "list_item_spec": { "item_name": "list_element", "item_type": "string", "item_optional": false, "item_default": "" } }, { "item_name": "item6", "item_type": "map", "item_optional": false, "item_default": {}, "map_item_spec": [ { "item_name": "value1", "item_type": "string", "item_optional": true, "item_default": "default" }, { "item_name": "value2", "item_type": "integer", "item_optional": true } ] } ], "commands": [ { "command_name": "print_message", "command_description": "Print the given message to stdout", "command_args": [ { "item_name": "message", "item_type": "string", "item_optional": false, "item_default": "" } ] }, { "command_name": "shutdown", "command_description": "Shut down Kea", "command_args": [] } ], "statistics": [ { "item_name": "dummy_time", "item_type": "string", "item_optional": false, "item_default": "1970-01-01T00:00:00Z", "item_title": "Dummy Time", "item_description": "A dummy date time", "item_format": "date-time" } ] } } kea-1.1.0/src/lib/config/tests/testdata/spec34.spec0000664000175000017500000000042112772017075016733 00000000000000{ "module_spec": { "module_name": "Spec34", "statistics": [ { "item_name": "dummy_str", "item_type": "string", "item_optional": false, "item_default": "Dummy", "item_description": "A dummy string" } ] } } kea-1.1.0/src/lib/config/tests/testdata/data22_5.data0000664000175000017500000000023312772017075017113 00000000000000{ "value1": 1, "value2": 2.3, "value3": true, "value4": "foo", "value5": [ 1, 2, 3 ], "value6": { "v61": "bar", "v62": "Break" } } kea-1.1.0/src/lib/config/tests/testdata/spec26.spec0000664000175000017500000000012412772017075016734 00000000000000{ "module_spec": { "module_name": "Spec26", "module_description": 1 } } kea-1.1.0/src/lib/config/tests/testdata/data22_2.data0000664000175000017500000000023512772017075017112 00000000000000{ "value1": "asdf", "value2": 2.3, "value3": true, "value4": "foo", "value5": [ 1, 2, 3 ], "value6": { "v61": "bar", "v62": true } } kea-1.1.0/src/lib/config/tests/testdata/data41_2.data0000664000175000017500000000044612772017075017117 00000000000000{ "zones": [ { "example.org": { "queries.tcp": 100, "queries.udp": 200 } }, { "example.net": { "queries.tcp": 300, "queries.udp": 400 } } ] } kea-1.1.0/src/lib/config/tests/testdata/spec17.spec0000664000175000017500000000051612772017075016741 00000000000000{ "module_spec": { "module_name": "Spec2", "commands": [ { "command_description": "Print the given message to stdout", "command_args": [ { "item_name": "message", "item_type": "string", "item_optional": false, "item_default": "" } ] } ] } } kea-1.1.0/src/lib/config/tests/testdata/spec1.spec0000664000175000017500000000006712772017075016653 00000000000000{ "module_spec": { "module_name": "Spec1" } } kea-1.1.0/src/lib/config/tests/testdata/spec30.spec0000664000175000017500000000300612772017075016731 00000000000000{ "module_spec": { "module_name": "lists", "module_description": "Logging options", "config_data": [ { "item_name": "first_list_items", "item_type": "list", "item_optional": false, "item_default": [], "list_item_spec": { "item_name": "first_list_item", "item_type": "map", "item_optional": false, "item_default": {}, "map_item_spec": [ { "item_name": "foo", "item_type": "string", "item_optional": false, "item_default": "foo" }, { "item_name": "second_list_items", "item_type": "list", "item_optional": false, "item_default": [], "list_item_spec": { "item_name": "second_list_item", "item_type": "map", "item_optional": false, "item_default": {}, "map_item_spec": [ { "item_name": "final_element", "item_type": "string", "item_optional": false, "item_default": "hello" } ] } } ] } } ] } } kea-1.1.0/src/lib/config/tests/testdata/spec31.spec0000664000175000017500000000445612772017075016744 00000000000000{ "module_spec": { "module_name": "lists", "module_description": "Logging options", "config_data": [ { "item_name": "first_list_items", "item_type": "list", "item_optional": false, "item_default": [], "list_item_spec": { "item_name": "first_list_item", "item_type": "map", "item_optional": false, "item_default": {}, "map_item_spec": [ { "item_name": "foo", "item_type": "string", "item_optional": false, "item_default": "foo" }, { "item_name": "second_list_items", "item_type": "list", "item_optional": false, "item_default": [], "list_item_spec": { "item_name": "second_list_item", "item_type": "map", "item_optional": false, "item_default": {}, "map_item_spec": [ { "item_name": "map_element", "item_type": "map", "item_optional": false, "item_default": {}, "map_item_spec": [ { "item_name": "list1", "item_type": "list", "item_optional": false, "item_default": [], "list_item_spec": { "item_name": "list2", "item_type": "list", "item_optional": false, "item_default": [], "list_item_spec": { "item_name": "number", "item_type": "integer", "item_optional": false, "item_default": 1 } } }] } ] } } ] } } ] } } kea-1.1.0/src/lib/config/tests/testdata/data32_2.data0000664000175000017500000000007312772017075017113 00000000000000{ "named_set_item": { "foo": "wrongtype", "bar": 2 } } kea-1.1.0/src/lib/config/tests/testdata/spec21.spec0000664000175000017500000000011212772017075016724 00000000000000{ "module_spec": { "module_name": "Spec2", "commands": 1 } } kea-1.1.0/src/lib/config/tests/testdata/Makefile.am0000664000175000017500000000303012772017075017011 00000000000000EXTRA_DIST = data22_1.data EXTRA_DIST += data22_2.data EXTRA_DIST += data22_3.data EXTRA_DIST += data22_4.data EXTRA_DIST += data22_5.data EXTRA_DIST += data22_6.data EXTRA_DIST += data22_7.data EXTRA_DIST += data22_8.data EXTRA_DIST += data22_9.data EXTRA_DIST += data22_10.data EXTRA_DIST += data32_1.data EXTRA_DIST += data32_2.data EXTRA_DIST += data32_3.data EXTRA_DIST += data33_1.data EXTRA_DIST += data33_2.data EXTRA_DIST += data41_1.data EXTRA_DIST += data41_2.data EXTRA_DIST += spec1.spec EXTRA_DIST += spec2.spec EXTRA_DIST += spec3.spec EXTRA_DIST += spec4.spec EXTRA_DIST += spec5.spec EXTRA_DIST += spec6.spec EXTRA_DIST += spec7.spec EXTRA_DIST += spec8.spec EXTRA_DIST += spec9.spec EXTRA_DIST += spec10.spec EXTRA_DIST += spec11.spec EXTRA_DIST += spec12.spec EXTRA_DIST += spec13.spec EXTRA_DIST += spec14.spec EXTRA_DIST += spec15.spec EXTRA_DIST += spec16.spec EXTRA_DIST += spec17.spec EXTRA_DIST += spec18.spec EXTRA_DIST += spec19.spec EXTRA_DIST += spec20.spec EXTRA_DIST += spec21.spec EXTRA_DIST += spec22.spec EXTRA_DIST += spec23.spec EXTRA_DIST += spec24.spec EXTRA_DIST += spec25.spec EXTRA_DIST += spec26.spec EXTRA_DIST += spec27.spec EXTRA_DIST += spec28.spec EXTRA_DIST += spec29.spec EXTRA_DIST += spec30.spec EXTRA_DIST += spec31.spec EXTRA_DIST += spec32.spec EXTRA_DIST += spec33.spec EXTRA_DIST += spec34.spec EXTRA_DIST += spec35.spec EXTRA_DIST += spec36.spec EXTRA_DIST += spec37.spec EXTRA_DIST += spec38.spec EXTRA_DIST += spec39.spec EXTRA_DIST += spec40.spec EXTRA_DIST += spec41.spec EXTRA_DIST += spec42.spec kea-1.1.0/src/lib/config/tests/testdata/data22_1.data0000664000175000017500000000033312772017075017110 00000000000000{ "value1": 1, "value2": 2.3, "value3": true, "value4": "foo", "value5": [ 1, 2, 3 ], "value6": { "v61": "bar", "v62": true }, "value9": { "v91": "hi", "v92": { "v92a": "Hi", "v92b": 3 } } } kea-1.1.0/src/lib/config/tests/testdata/spec27.spec0000664000175000017500000000703112772017075016741 00000000000000{ "module_spec": { "module_name": "Spec27", "commands": [ { "command_name": "cmd1", "command_description": "command_for_unittest", "command_args": [ { "item_name": "value1", "item_type": "integer", "item_optional": false, "item_default": 9 }, { "item_name": "value2", "item_type": "real", "item_optional": false, "item_default": 9.9 }, { "item_name": "value3", "item_type": "boolean", "item_optional": false, "item_default": false }, { "item_name": "value4", "item_type": "string", "item_optional": false, "item_default": "default_string" }, { "item_name": "value5", "item_type": "list", "item_optional": false, "item_default": [ "a", "b" ], "list_item_spec": { "item_name": "list_element", "item_type": "integer", "item_optional": false, "item_default": 8 } }, { "item_name": "value6", "item_type": "map", "item_optional": false, "item_default": {}, "map_item_spec": [ { "item_name": "v61", "item_type": "string", "item_optional": false, "item_default": "def" }, { "item_name": "v62", "item_type": "boolean", "item_optional": false, "item_default": false } ] }, { "item_name": "value7", "item_type": "list", "item_optional": true, "item_default": [ ], "list_item_spec": { "item_name": "list_element", "item_type": "any", "item_optional": true } }, { "item_name": "value8", "item_type": "list", "item_optional": true, "item_default": [ ], "list_item_spec": { "item_name": "list_element", "item_type": "map", "item_optional": true, "item_default": { "a": "b" }, "map_item_spec": [ { "item_name": "a", "item_type": "string", "item_optional": true, "item_default": "empty" } ] } }, { "item_name": "value9", "item_type": "map", "item_optional": false, "item_default": {}, "map_item_spec": [ { "item_name": "v91", "item_type": "string", "item_optional": false, "item_default": "def" }, { "item_name": "v92", "item_type": "map", "item_optional": false, "item_default": {}, "map_item_spec": [ { "item_name": "v92a", "item_type": "string", "item_optional": false, "item_default": "Hello" } , { "item_name": "v92b", "item_type": "integer", "item_optional": false, "item_default": 56176 } ] } ] } ] } ] } } kea-1.1.0/src/lib/config/tests/testdata/spec15.spec0000664000175000017500000000032312772017075016733 00000000000000{ "module_spec": { "module_name": "Spec2", "config_data": [ { "item_name": "item1", "item_type": "badname", "item_optional": false, "item_default": 1 } ] } } kea-1.1.0/src/lib/config/tests/testdata/data32_3.data0000664000175000017500000000003512772017075017112 00000000000000{ "named_set_item": [] } kea-1.1.0/src/lib/config/tests/testdata/spec39.spec0000664000175000017500000000065212772017075016746 00000000000000{ "module_spec": { "module_name": "Spec39", "config_data": [ { "item_name": "list", "item_type": "list", "item_optional": false, "item_default": [], "list_item_spec": { "item_name": "list_item", "item_type": "boolean", "item_optional": false, "item_default": false } } ], "commands": [], "statistics": [] } } kea-1.1.0/src/lib/config/tests/testdata/data22_6.data0000664000175000017500000000040212772017075017112 00000000000000{ "value1": 1, "value2": 2.3, "value3": true, "value4": "foo", "value5": [ 1, 2, 3 ], "value6": { "v61": "bar", "v62": true }, "value7": [ 1, 2.2, "str", true ], "value9": { "v91": "hi", "v92": { "v92a": "Hi", "v92b": 3 } } } kea-1.1.0/src/lib/config/tests/testdata/spec32.spec0000664000175000017500000000375012772017075016741 00000000000000{ "module_spec": { "module_name": "Spec32", "config_data": [ { "item_name": "named_set_item", "item_type": "named_set", "item_optional": false, "item_default": { "a": 1, "b": 2 }, "named_set_item_spec": { "item_name": "named_set_element", "item_type": "integer", "item_optional": false, "item_default": 3 } }, { "item_name": "named_set_item2", "item_type": "named_set", "item_optional": true, "item_default": { }, "named_set_item_spec": { "item_name": "named_set_element", "item_type": "map", "item_optional": false, "item_default": {}, "map_item_spec": [ { "item_name": "first", "item_type": "integer", "item_optional": true }, { "item_name": "second", "item_type": "string", "item_optional": true } ] } }, { "item_name": "named_set_item3", "item_type": "named_set", "item_optional": true, "item_default": { "values": [ 1, 2, 3 ] }, "named_set_item_spec": { "item_name": "named_set_element", "item_type": "list", "item_optional": false, "item_default": [], "list_item_spec": { "item_name": "list_value", "item_type": "integer", "item_optional": true } } }, { "item_name": "named_set_item4", "item_type": "named_set", "item_optional": true, "item_default": {}, "named_set_item_spec": { "item_name": "named_set_element", "item_type": "named_set", "item_optional": false, "item_default": { "a": 1, "b": 2 }, "named_set_item_spec": { "item_name": "named_set_element", "item_type": "integer", "item_optional": true } } } ] } } kea-1.1.0/src/lib/config/tests/testdata/data22_9.data0000664000175000017500000000045012772017075017120 00000000000000{ "value1": 1, "value2": 2.3, "value3": true, "value4": "foo", "value5": [ 1, 2, 3 ], "value6": { "v61": "bar", "v62": true }, "value8": [ { "a": "d" }, { "a": "e" } ], "value9": { "v91": "hi", "v92": { "v92a": "Hi", "v92b": 3 } }, "value_does_not_exist": 1 } kea-1.1.0/src/lib/config/tests/testdata/spec33.spec0000664000175000017500000000251012772017075016733 00000000000000{ "module_spec": { "module_name": "Spec33", "statistics": [ { "item_name": "dummy_str", "item_type": "string", "item_optional": false, "item_default": "Dummy", "item_title": "Dummy String", "item_description": "A dummy string" }, { "item_name": "dummy_int", "item_type": "integer", "item_optional": false, "item_default": 0, "item_title": "Dummy Integer", "item_description": "A dummy integer" }, { "item_name": "dummy_datetime", "item_type": "string", "item_optional": false, "item_default": "1970-01-01T00:00:00Z", "item_title": "Dummy DateTime", "item_description": "A dummy datetime", "item_format": "date-time" }, { "item_name": "dummy_date", "item_type": "string", "item_optional": false, "item_default": "1970-01-01", "item_title": "Dummy Date", "item_description": "A dummy date", "item_format": "date" }, { "item_name": "dummy_time", "item_type": "string", "item_optional": false, "item_default": "00:00:00", "item_title": "Dummy Time", "item_description": "A dummy time", "item_format": "time" } ] } } kea-1.1.0/src/lib/config/tests/testdata/spec7.spec0000664000175000017500000000003412772017075016653 00000000000000{ "module_spec": { } } kea-1.1.0/src/lib/config/tests/testdata/spec22.spec0000664000175000017500000000576712772017075016752 00000000000000{ "module_spec": { "module_name": "Spec22", "config_data": [ { "item_name": "value1", "item_type": "integer", "item_optional": false, "item_default": 9 }, { "item_name": "value2", "item_type": "real", "item_optional": false, "item_default": 9.9 }, { "item_name": "value3", "item_type": "boolean", "item_optional": false, "item_default": false }, { "item_name": "value4", "item_type": "string", "item_optional": false, "item_default": "default_string" }, { "item_name": "value5", "item_type": "list", "item_optional": false, "item_default": [ "a", "b" ], "list_item_spec": { "item_name": "list_element", "item_type": "integer", "item_optional": false, "item_default": 8 } }, { "item_name": "value6", "item_type": "map", "item_optional": false, "item_default": {}, "map_item_spec": [ { "item_name": "v61", "item_type": "string", "item_optional": false, "item_default": "def" }, { "item_name": "v62", "item_type": "boolean", "item_optional": false, "item_default": false } ] }, { "item_name": "value7", "item_type": "list", "item_optional": true, "item_default": [ ], "list_item_spec": { "item_name": "list_element", "item_type": "any", "item_optional": true } }, { "item_name": "value8", "item_type": "list", "item_optional": true, "item_default": [ ], "list_item_spec": { "item_name": "list_element", "item_type": "map", "item_optional": true, "item_default": { "a": "b" }, "map_item_spec": [ { "item_name": "a", "item_type": "string", "item_optional": true, "item_default": "empty" } ] } }, { "item_name": "value9", "item_type": "map", "item_optional": false, "item_default": { "v91": "def", "v92": {} }, "map_item_spec": [ { "item_name": "v91", "item_type": "string", "item_optional": false, "item_default": "def" }, { "item_name": "v92", "item_type": "map", "item_optional": false, "item_default": {}, "map_item_spec": [ { "item_name": "v92a", "item_type": "string", "item_optional": false, "item_default": "Hello" } , { "item_name": "v92b", "item_type": "integer", "item_optional": false, "item_default": 56176 } ] } ] } ] } } kea-1.1.0/src/lib/config/tests/testdata/spec14.spec0000664000175000017500000000031712772017075016735 00000000000000{ "module_spec": { "module_name": "Spec2", "config_data": [ { "item_name": "item1", "item_type": "map", "item_optional": false, "item_default": 1 } ] } } kea-1.1.0/src/lib/config/tests/testdata/spec4.spec0000664000175000017500000000026312772017075016654 00000000000000{ "module_spec": { "module_name": "Spec2", "config_data": [ { "item_name": "item1", "item_optional": false, "item_default": 1 } ] } } kea-1.1.0/src/lib/config/tests/testdata/spec29.spec0000664000175000017500000000144012772017075016741 00000000000000{ "module_spec": { "module_name": "Spec29", "config_data": [ { "item_name": "item1", "item_type": "integer", "item_optional": false, "item_default": 1 } ], "commands": [ { "command_name": "good_command", "command_description": "A good command", "command_args": [] }, { "command_name": "bad_command", "command_description": "A bad command", "command_args": [] }, { "command_name": "command_with_arg", "command_description": "A command with an (integer) argument", "command_args": [ { "item_name": "number", "item_type": "integer", "item_optional": true, "item_default": 1 } ] } ] } } kea-1.1.0/src/lib/config/tests/testdata/spec42.spec0000664000175000017500000000054612772017075016742 00000000000000{ "module_spec": { "module_name": "Spec42", "config_data": [ { "item_name": "list_item", "item_type": "list", "item_optional": true, "list_item_spec": { "item_name": "list_element", "item_type": "string", "item_optional": false, "item_default": "" } } ] } } kea-1.1.0/src/lib/config/tests/testdata/spec10.spec0000664000175000017500000000032012772017075016723 00000000000000{ "module_spec": { "module_name": "Spec2", "config_data": [ { "item_name": "item1", "item_type": "real", "item_optional": false, "item_default": 1 } ] } } kea-1.1.0/src/lib/config/tests/testdata/spec13.spec0000664000175000017500000000032012772017075016726 00000000000000{ "module_spec": { "module_name": "Spec2", "config_data": [ { "item_name": "item1", "item_type": "list", "item_optional": false, "item_default": 1 } ] } } kea-1.1.0/src/lib/config/tests/testdata/spec20.spec0000664000175000017500000000057512772017075016740 00000000000000{ "module_spec": { "module_name": "Spec2", "commands": [ { "command_name": "print_message", "command_description": "Print the given message to stdout", "command_args": [ { "item_name": "message", "item_type": "somethingbad", "item_optional": false, "item_default": "" } ] } ] } } kea-1.1.0/src/lib/config/tests/testdata/spec19.spec0000664000175000017500000000034712772017075016745 00000000000000{ "module_spec": { "module_name": "Spec2", "commands": [ { "command_name": "print_message", "command_description": "Print the given message to stdout", "command_args": 1 } ] } } kea-1.1.0/src/lib/config/tests/testdata/spec18.spec0000664000175000017500000000031412772017075016736 00000000000000{ "module_spec": { "module_name": "Spec2", "commands": [ { "command_name": "print_message", "command_description": "Print the given message to stdout" } ] } } kea-1.1.0/src/lib/config/tests/testdata/spec12.spec0000664000175000017500000000032212772017075016727 00000000000000{ "module_spec": { "module_name": "Spec2", "config_data": [ { "item_name": "item1", "item_type": "string", "item_optional": false, "item_default": 1 } ] } } kea-1.1.0/src/lib/config/tests/testdata/data33_2.data0000664000175000017500000000021412772017075017111 00000000000000{ "dummy_str": "Dummy String", "dummy_int": 118, "dummy_datetime": "xxxx", "dummy_date": "xxxx", "dummy_time": "xxxx" } kea-1.1.0/src/lib/config/tests/testdata/spec5.spec0000664000175000017500000000026312772017075016655 00000000000000{ "module_spec": { "module_name": "Spec2", "config_data": [ { "item_name": "item1", "item_type": "integer", "item_default": 1 } ] } } kea-1.1.0/src/lib/config/tests/testdata/data32_1.data0000664000175000017500000000006112772017075017107 00000000000000{ "named_set_item": { "foo": 1, "bar": 2 } } kea-1.1.0/src/lib/config/tests/testdata/spec35.spec0000664000175000017500000000041212772017075016734 00000000000000{ "module_spec": { "module_name": "Spec35", "statistics": [ { "item_name": "dummy_str", "item_type": "string", "item_optional": false, "item_default": "Dummy", "item_title": "Dummy String" } ] } } kea-1.1.0/src/lib/config/tests/testdata/spec6.spec0000664000175000017500000000027012772017075016654 00000000000000{ "module_spec": { "module_name": "Spec2", "config_data": [ { "item_name": "item1", "item_type": "integer", "item_optional": false } ] } } kea-1.1.0/src/lib/config/tests/testdata/spec23.spec0000664000175000017500000000056712772017075016744 00000000000000{ "module_spec": { "module_name": "Spec2", "commands": [ { "command_name": "print_message", "command_description": "Print the given message to stdout", "command_args": [ { "item_name": "message", "item_type": "string", "item_optional": false, "item_default": "" } ] } ] } } kea-1.1.0/src/lib/config/tests/testdata/data22_7.data0000664000175000017500000000041112772017075017113 00000000000000{ "value1": 1, "value2": 2.3, "value3": true, "value4": "foo", "value5": [ 1, 2, 3 ], "value6": { "v61": "bar", "v62": true }, "value8": [ { "a": "d" }, { "a": "e" } ], "value9": { "v91": "hi", "v92": { "v92a": "Hi", "v92b": 3 } } } kea-1.1.0/src/lib/config/tests/testdata/spec41.spec0000664000175000017500000000156212772017075016740 00000000000000{ "module_spec": { "module_name": "Spec40", "statistics": [ { "item_name": "zones", "item_type": "named_set", "item_optional": false, "item_default": { }, "item_title": "Dummy name set", "item_description": "A dummy name set", "named_set_item_spec": { "item_name": "zonename", "item_type": "map", "item_optional": false, "item_default": { }, "map_item_spec": [ { "item_name": "queries.tcp", "item_optional": false, "item_type": "integer", "item_default": 0 }, { "item_name": "queries.udp", "item_optional": false, "item_type": "integer", "item_default": 0 } ] } } ] } } kea-1.1.0/src/lib/config/tests/testdata/data22_10.data0000664000175000017500000000043512772017075017173 00000000000000{ "version": 123, "value1": 1, "value2": 2.3, "value3": true, "value4": "foo", "value5": [ 1, 2, 3 ], "value6": { "v61": "bar", "v62": true }, "value8": [ { "a": "d" }, { "a": "e" } ], "value9": { "v91": "hi", "v92": { "v92a": "Hi", "v92b": 3 } } } kea-1.1.0/src/lib/config/tests/testdata/data41_1.data0000664000175000017500000000033612772017075017114 00000000000000{ "zones": { "example.org": { "queries.tcp": 100, "queries.udp": 200 }, "example.net": { "queries.tcp": 300, "queries.udp": 400 } } } kea-1.1.0/src/lib/config/tests/testdata/spec8.spec0000664000175000017500000000000512772017075016652 00000000000000{ } kea-1.1.0/src/lib/config/tests/testdata/spec16.spec0000664000175000017500000000011512772017075016733 00000000000000{ "module_spec": { "module_name": "Spec2", "config_data": 1 } } kea-1.1.0/src/lib/config/tests/testdata/spec9.spec0000664000175000017500000000033012772017075016654 00000000000000{ "module_spec": { "module_name": "Spec2", "config_data": [ { "item_name": "item1", "item_type": "integer", "item_optional": false, "item_default": "asdf" } ] } } kea-1.1.0/src/lib/config/tests/testdata/spec3.spec0000664000175000017500000000027512772017075016656 00000000000000{ "module_spec": { "module_name": "Spec3", "config_data": [ { "item_type": "integer", "item_optional": false, "item_default": 1 } ] } } kea-1.1.0/src/lib/config/tests/testdata/data22_4.data0000664000175000017500000000023212772017075017111 00000000000000{ "value1": 1, "value2": 2.3, "value3": true, "value4": "foo", "value5": [ 1, 2, "a" ], "value6": { "v61": "bar", "v62": true } } kea-1.1.0/src/lib/config/tests/testdata/data22_3.data0000664000175000017500000000023212772017075017110 00000000000000{ "value1": 1, "value2": false, "value3": true, "value4": "foo", "value5": [ 1, 2, 3 ], "value6": { "v61": "bar", "v62": true } } kea-1.1.0/src/lib/config/tests/testdata/data22_8.data0000664000175000017500000000040712772017075017121 00000000000000{ "value1": 1, "value2": 2.3, "value3": true, "value4": "foo", "value5": [ 1, 2, 3 ], "value6": { "v61": "bar", "v62": true }, "value8": [ { "a": "d" }, { "a": 1 } ], "value9": { "v91": "hi", "v92": { "v92a": "Hi", "v92b": 3 } } } kea-1.1.0/src/lib/config/tests/run_unittests.cc0000664000175000017500000000101412772017075016401 00000000000000// Copyright (C) 2009-2015 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 #include #include int main(int argc, char* argv[]) { ::testing::InitGoogleTest(&argc, argv); isc::log::initLogger(); return (isc::util::unittests::run_all()); } kea-1.1.0/src/lib/config/command_mgr.cc0000664000175000017500000001616412772445242014611 00000000000000// Copyright (C) 2015-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 #include #include #include #include #include #include using namespace isc::data; namespace isc { namespace config { CommandMgr::CommandMgr() { registerCommand("list-commands", boost::bind(&CommandMgr::listCommandsHandler, this, _1, _2)); } CommandSocketPtr CommandMgr::openCommandSocket(const isc::data::ConstElementPtr& socket_info) { if (socket_) { isc_throw(SocketError, "There is already a control socket open"); } socket_ = CommandSocketFactory::create(socket_info); return (socket_); } void CommandMgr::closeCommandSocket() { // First, let's close the socket for incoming new connections. if (socket_) { socket_->close(); socket_.reset(); } // Now let's close all existing connections that we may have. for (std::list::iterator conn = connections_.begin(); conn != connections_.end(); ++conn) { (*conn)->close(); } connections_.clear(); } void CommandMgr::addConnection(const CommandSocketPtr& conn) { connections_.push_back(conn); } bool CommandMgr::closeConnection(int fd) { // Let's iterate over all currently registered connections. for (std::list::iterator conn = connections_.begin(); conn != connections_.end(); ++conn) { // If found, close it. if ((*conn)->getFD() == fd) { (*conn)->close(); connections_.erase(conn); return (true); } } return (false); } CommandMgr& CommandMgr::instance() { static CommandMgr cmd_mgr; return (cmd_mgr); } void CommandMgr::registerCommand(const std::string& cmd, CommandHandler handler) { if (!handler) { isc_throw(InvalidCommandHandler, "Specified command handler is NULL"); } HandlerContainer::const_iterator it = handlers_.find(cmd); if (it != handlers_.end()) { isc_throw(InvalidCommandName, "Handler for command '" << cmd << "' is already installed."); } handlers_.insert(make_pair(cmd, handler)); LOG_DEBUG(command_logger, DBG_COMMAND, COMMAND_REGISTERED).arg(cmd); } void CommandMgr::deregisterCommand(const std::string& cmd) { if (cmd == "list-commands") { isc_throw(InvalidCommandName, "Can't uninstall internal command 'list-commands'"); } HandlerContainer::iterator it = handlers_.find(cmd); if (it == handlers_.end()) { isc_throw(InvalidCommandName, "Handler for command '" << cmd << "' not found."); } handlers_.erase(it); LOG_DEBUG(command_logger, DBG_COMMAND, COMMAND_DEREGISTERED).arg(cmd); } void CommandMgr::deregisterAll() { // No need to log anything here. deregisterAll is not used in production // code, just in tests. handlers_.clear(); registerCommand("list-commands", boost::bind(&CommandMgr::listCommandsHandler, this, _1, _2)); } void CommandMgr::commandReader(int sockfd) { /// @todo: We do not handle commands that are larger than 64K. // We should not expect commands bigger than 64K. char buf[65536]; memset(buf, 0, sizeof(buf)); ConstElementPtr cmd, rsp; // Read incoming data. int rval = read(sockfd, buf, sizeof(buf)); if (rval < 0) { // Read failed LOG_ERROR(command_logger, COMMAND_SOCKET_READ_FAIL).arg(rval).arg(sockfd); /// @todo: Should we close the connection, similar to what is already /// being done for rval == 0? return; } else if (rval == 0) { // Remove it from the active connections list. instance().closeConnection(sockfd); return; } LOG_DEBUG(command_logger, DBG_COMMAND, COMMAND_SOCKET_READ).arg(rval).arg(sockfd); // Ok, we received something. Let's see if we can make any sense of it. try { // Try to interpret it as JSON. std::string sbuf(buf, static_cast(rval)); cmd = Element::fromJSON(sbuf, true); // If successful, then process it as a command. rsp = CommandMgr::instance().processCommand(cmd); } catch (const Exception& ex) { LOG_WARN(command_logger, COMMAND_PROCESS_ERROR1).arg(ex.what()); rsp = createAnswer(CONTROL_RESULT_ERROR, std::string(ex.what())); } if (!rsp) { LOG_WARN(command_logger, COMMAND_RESPONSE_ERROR); return; } // Let's convert JSON response to text. Note that at this stage // the rsp pointer is always set. std::string txt = rsp->str(); size_t len = txt.length(); if (len > 65535) { // Hmm, our response is too large. Let's send the first // 64KB and hope for the best. LOG_ERROR(command_logger, COMMAND_SOCKET_RESPONSE_TOOLARGE).arg(len); len = 65535; } // Send the data back over socket. rval = write(sockfd, txt.c_str(), len); LOG_DEBUG(command_logger, DBG_COMMAND, COMMAND_SOCKET_WRITE).arg(len).arg(sockfd); if (rval < 0) { // Response transmission failed. Since the response failed, it doesn't // make sense to send any status codes. Let's log it and be done with // it. LOG_ERROR(command_logger, COMMAND_SOCKET_WRITE_FAIL).arg(len).arg(sockfd); } } isc::data::ConstElementPtr CommandMgr::processCommand(const isc::data::ConstElementPtr& cmd) { if (!cmd) { return (createAnswer(CONTROL_RESULT_ERROR, "Command processing failed: NULL command parameter")); } try { ConstElementPtr arg; std::string name = parseCommand(arg, cmd); LOG_INFO(command_logger, COMMAND_RECEIVED).arg(name); HandlerContainer::const_iterator it = handlers_.find(name); if (it == handlers_.end()) { // Ok, there's no such command. return (createAnswer(CONTROL_RESULT_ERROR, "'" + name + "' command not supported.")); } // Call the actual handler and return whatever it returned return (it->second(name, arg)); } catch (const Exception& e) { LOG_WARN(command_logger, COMMAND_PROCESS_ERROR2).arg(e.what()); return (createAnswer(CONTROL_RESULT_ERROR, std::string("Error during command processing:") + e.what())); } } isc::data::ConstElementPtr CommandMgr::listCommandsHandler(const std::string& name, const isc::data::ConstElementPtr& params) { using namespace isc::data; ElementPtr commands = Element::createList(); for (HandlerContainer::const_iterator it = handlers_.begin(); it != handlers_.end(); ++it) { commands->add(Element::create(it->first)); } return (createAnswer(CONTROL_RESULT_SUCCESS, commands)); } }; // end of isc::config }; // end of isc kea-1.1.0/src/lib/config/command-socket.dox0000664000175000017500000001700712772017075015433 00000000000000// Copyright (C) 2015 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/. /** @page ctrlSocket Control Channel @section ctrlSocketOverview Control Channel Overview In many cases it is useful to manage certain aspects of the DHCP servers while they are running. In Kea, this may be done via the Control Channel. Control Channel allows an external entity (e.g. a tool run by a sysadmin or a script) to issue commands to the server which can influence its behavior or retreive information from it. Several notable examples envisioned are: reconfiguration, statistics retrieval and manipulation, and shutdown. Communication over Control Channel is conducted using JSON structures. As of Kea 0.9.2, the only supported communication channel is UNIX stream socket, but additional types may be added in the future. If configured, Kea will open a socket and will listen for any incoming connections. A process connecting to this socket is expected to send JSON commands structured as follows: @code { "command": "foo", "arguments": { "param_foo": "value1", "param_bar": "value2", ... } } @endcode - command - is the name of command to execute and is mandatory. - arguments - contain a single parameter or a map or parameters required to carry out the given command. The exact content and format is command specific. The server will process the incoming command and then send a response of the form: @code { "result": 0|1, "text": "textual description", "arguments": { "argument1": "value1", "argument2": "value2", ... } } @endcode - result - indicates the outcome of the command. A value of 0 means a success while any non-zero value designates an error. Currently 1 is used as a generic error, but additional error codes may be added in the future. - text field - typically appears when result is non-zero and contains description of the error encountered. - arguments - is a map of additional data values returned by the server, specific to the command issue. The map is always present, even if it contains no data values. @section ctrlSocketClient Using Control Channel Here are two examples of how to access the Control Channel: 1. Use socat tool, which is available in many Linux and BSD distributions. See http://www.dest-unreach.org/socat/ for details. To use it: @code socat UNIX:/var/run/kea/kea4.sock - @endcode You then can type JSON commands and get responses (also in JSON format). 2. Here's an example C code that connects and gets a list of supported commands: @code // Copyright (C) 2015 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 #include #include #include #include int main(int argc, const char* argv[]) { if (argc != 2) { printf("Usage: %s socket_path\n", argv[0]); return (1); } // Create UNIX stream socket. int socket_fd; if ((socket_fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { perror("Failed to create UNIX stream"); return (1); } // Specify the address to connect to (unix path) struct sockaddr_un srv_addr; memset(&srv_addr, 0, sizeof(struct sockaddr_un)); srv_addr.sun_family = AF_UNIX; strcpy(srv_addr.sun_path, argv[1]); socklen_t len = sizeof(srv_addr); // Try to connect. if (connect(socket_fd, (struct sockaddr*) &srv_addr, len) == -1) { perror("Failed to connect"); return (1); } // Send a command to list all available commands. char buf[1024]; sprintf(buf, "{ \"command\": \"list-commands\" }"); int bytes_sent = send(socket_fd, buf, strlen(buf), 0); printf("%d bytes sent\n", bytes_sent); // Receive a response (should be JSON formatted list of commands) int bytes_rcvd = recv(socket_fd, buf, sizeof(buf), 0); printf("%d bytes received: [%s]\n", bytes_rcvd, buf); // Close the socket close(socket_fd); return 0; } @endcode @section ctrlSocketImpl Control Channel Implementation Control Channel is implemented in @ref isc::config::CommandMgr. It is a signleton class that allows registration of callbacks that handle specific commands. It internally supports a single command: @c list-commands that returns a list of supported commands. This component is expected to be shared among all daemons. There are 3 main methods that are expected to be used by developers: - @ref isc::config::CommandMgr::registerCommand, which allows registration of additional commands. - @ref isc::config::CommandMgr::deregisterCommand, which allows removing previously registered command. - @ref isc::config::CommandMgr::processCommand, which allows handling specified command. There are also two methods for managing control sockets. They are not expected to be used directly, unless someone implements a new Control Channel (e.g. TCP or HTTPS connection): - @ref isc::config::CommandMgr::openCommandSocket that passes structure defined in the configuration file. Currently only two parameters are supported: socket-type (which must contain value 'unix') and socket-name (which contains unix path for the named socket to be created). This method calls @ref isc::config::CommandSocketFactory::create method, which parses the parameters and instantiates one object from a class derived from @ref isc::config::CommandSocket. Again, currently only UNIX type is supported, but the factory class is expected to be extended to cover additional types. - @ref isc::config::CommandMgr::closeCommandSocket() - it is used to close the socket. It calls close method on the @ref isc::config::CommandSocket object, if one exists. In particular, for UNIX socket, it also deletes the file after socket was closed. @section ctrlSocketConnections Accepting connections Control Channel is connection oriented communication. In that sense it is different than all other communications supported so far in Kea. To facilitate connections, several mechanisms were implemented. Intially a single UNIX socket it opened (see @c isc::config::UnixCommandSocket in src/lib/config/command_socket_factory.cc). Its @ref isc::config::UnixCommandSocket::receiveHandler callback method is installed in @ref isc::dhcp::IfaceMgr to process incoming connections. When the select call in @ref isc::dhcp::IfaceMgr::receive4 indicates that there is some data to be processed, this callback calls accept, which creates a new socket for handling this particular incoming connection. Once the socket descriptor is known, a new instance of @ref isc::config::ConnectionSocket is created to represent that socket (and the whole ongoing connection). It installs another callback (@ref isc::config::ConnectionSocket::receiveHandler that calls (@ref isc::config::CommandMgr::commandReader) that will process incoming data or will close the socket when necessary. CommandReader reads data from incoming socket and attempts to parse it as JSON structures. If successful, it calls isc::config::CommandMgr::processCommand(), serializes the structure returned and attempts to send it back. @todo Currently commands and responses up to 64KB are supported. It was deemed sufficient for the current needs, but in the future we may need to extend it to handle bigger structures. */ kea-1.1.0/src/lib/config/config_log.cc0000664000175000017500000000073412772017075014427 00000000000000// Copyright (C) 2011-2015 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/. /// Defines the logger used by the config lib #include "config/config_log.h" namespace isc { namespace config { isc::log::Logger command_logger("commands"); } // namespace nsas } // namespace isc kea-1.1.0/src/lib/asiolink/0000775000175000017500000000000012772742661012440 500000000000000kea-1.1.0/src/lib/asiolink/Makefile.in0000664000175000017500000010656112772742615014435 00000000000000# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = src/lib/asiolink DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/depcomp $(libkea_asiolink_include_HEADERS) \ README ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4macros/ax_boost_for_kea.m4 \ $(top_srcdir)/m4macros/ax_isc_rpath.m4 \ $(top_srcdir)/m4macros/libtool.m4 \ $(top_srcdir)/m4macros/ltoptions.m4 \ $(top_srcdir)/m4macros/ltsugar.m4 \ $(top_srcdir)/m4macros/ltversion.m4 \ $(top_srcdir)/m4macros/lt~obsolete.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(libdir)" \ "$(DESTDIR)$(libkea_asiolink_includedir)" LTLIBRARIES = $(lib_LTLIBRARIES) am__DEPENDENCIES_1 = libkea_asiolink_la_DEPENDENCIES = \ $(top_builddir)/src/lib/exceptions/libkea-exceptions.la \ $(am__DEPENDENCIES_1) am_libkea_asiolink_la_OBJECTS = libkea_asiolink_la-interval_timer.lo \ libkea_asiolink_la-io_address.lo \ libkea_asiolink_la-io_endpoint.lo \ libkea_asiolink_la-io_service.lo \ libkea_asiolink_la-io_socket.lo libkea_asiolink_la_OBJECTS = $(am_libkea_asiolink_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = libkea_asiolink_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(libkea_asiolink_la_CXXFLAGS) $(CXXFLAGS) \ $(libkea_asiolink_la_LDFLAGS) $(LDFLAGS) -o $@ AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CXXFLAGS) $(CXXFLAGS) AM_V_CXX = $(am__v_CXX_@AM_V@) am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@) am__v_CXX_0 = @echo " CXX " $@; am__v_CXX_1 = CXXLD = $(CXX) CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CXXLD = $(am__v_CXXLD_@AM_V@) am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@) am__v_CXXLD_0 = @echo " CXXLD " $@; am__v_CXXLD_1 = COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libkea_asiolink_la_SOURCES) DIST_SOURCES = $(libkea_asiolink_la_SOURCES) RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ install-exec-recursive install-html-recursive \ install-info-recursive install-pdf-recursive \ install-ps-recursive install-recursive installcheck-recursive \ installdirs-recursive pdf-recursive ps-recursive \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac HEADERS = $(libkea_asiolink_include_HEADERS) RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ distdir am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DIST_SUBDIRS = $(SUBDIRS) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ASCIIDOC = @ASCIIDOC@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BOOST_INCLUDES = @BOOST_INCLUDES@ BOOST_LIBS = @BOOST_LIBS@ BOTAN_TOOL = @BOTAN_TOOL@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CQL_CPPFLAGS = @CQL_CPPFLAGS@ CQL_LIBS = @CQL_LIBS@ CRYPTO_CFLAGS = @CRYPTO_CFLAGS@ CRYPTO_INCLUDES = @CRYPTO_INCLUDES@ CRYPTO_LDFLAGS = @CRYPTO_LDFLAGS@ CRYPTO_LIBS = @CRYPTO_LIBS@ CRYPTO_PACKAGE = @CRYPTO_PACKAGE@ CRYPTO_RPATH = @CRYPTO_RPATH@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DBLATEX = @DBLATEX@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DISTCHECK_BOOST_CONFIGURE_FLAG = @DISTCHECK_BOOST_CONFIGURE_FLAG@ DISTCHECK_CRYPTO_CONFIGURE_FLAG = @DISTCHECK_CRYPTO_CONFIGURE_FLAG@ DISTCHECK_GTEST_CONFIGURE_FLAG = @DISTCHECK_GTEST_CONFIGURE_FLAG@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ ELINKS = @ELINKS@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GENHTML = @GENHTML@ GREP = @GREP@ GTEST_CONFIG = @GTEST_CONFIG@ GTEST_INCLUDES = @GTEST_INCLUDES@ GTEST_LDADD = @GTEST_LDADD@ GTEST_LDFLAGS = @GTEST_LDFLAGS@ GTEST_SOURCE = @GTEST_SOURCE@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ KEA_CXXFLAGS = @KEA_CXXFLAGS@ LCOV = @LCOV@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LEXLIB = @LEXLIB@ LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LOG4CPLUS_INCLUDES = @LOG4CPLUS_INCLUDES@ LOG4CPLUS_LIBS = @LOG4CPLUS_LIBS@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ MYSQL_LIBS = @MYSQL_LIBS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PERL = @PERL@ PGSQL_CPPFLAGS = @PGSQL_CPPFLAGS@ PGSQL_LIBS = @PGSQL_LIBS@ PKG_CONFIG = @PKG_CONFIG@ PLANTUML = @PLANTUML@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SEP = @SEP@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ USE_LCOV = @USE_LCOV@ VALGRIND = @VALGRIND@ VERSION = @VERSION@ WARNING_GCC_44_STRICT_ALIASING_CFLAG = @WARNING_GCC_44_STRICT_ALIASING_CFLAG@ XSLTPROC = @XSLTPROC@ YACC = @YACC@ YFLAGS = @YFLAGS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ SUBDIRS = . tests AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib \ $(BOOST_INCLUDES) AM_CXXFLAGS = $(KEA_CXXFLAGS) CLEANFILES = *.gcno *.gcda # This is a wrapper library. # The ASIO header files have some code fragments that would hit # gcc's unused-parameter warning, which would make the build fail # with -Werror (our default setting). lib_LTLIBRARIES = libkea-asiolink.la libkea_asiolink_la_LDFLAGS = -no-undefined -version-info 3:0:0 libkea_asiolink_la_SOURCES = asiolink.h asio_wrapper.h dummy_io_cb.h \ interval_timer.cc interval_timer.h io_address.cc io_address.h \ io_asio_socket.h io_endpoint.cc io_endpoint.h io_error.h \ io_service.h io_service.cc io_socket.h io_socket.cc \ tcp_endpoint.h tcp_socket.h udp_endpoint.h udp_socket.h # Note: the ordering matters: -Wno-... must follow -Wextra (defined in # KEA_CXXFLAGS) libkea_asiolink_la_CXXFLAGS = $(AM_CXXFLAGS) libkea_asiolink_la_CPPFLAGS = $(AM_CPPFLAGS) libkea_asiolink_la_LIBADD = \ $(top_builddir)/src/lib/exceptions/libkea-exceptions.la \ $(BOOST_LIBS) # IOAddress is sometimes used in user-library code libkea_asiolink_includedir = $(pkgincludedir)/asiolink libkea_asiolink_include_HEADERS = io_address.h all: all-recursive .SUFFIXES: .SUFFIXES: .cc .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/lib/asiolink/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign src/lib/asiolink/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } libkea-asiolink.la: $(libkea_asiolink_la_OBJECTS) $(libkea_asiolink_la_DEPENDENCIES) $(EXTRA_libkea_asiolink_la_DEPENDENCIES) $(AM_V_CXXLD)$(libkea_asiolink_la_LINK) -rpath $(libdir) $(libkea_asiolink_la_OBJECTS) $(libkea_asiolink_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libkea_asiolink_la-interval_timer.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libkea_asiolink_la-io_address.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libkea_asiolink_la-io_endpoint.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libkea_asiolink_la-io_service.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libkea_asiolink_la-io_socket.Plo@am__quote@ .cc.o: @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $< .cc.obj: @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .cc.lo: @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $< libkea_asiolink_la-interval_timer.lo: interval_timer.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkea_asiolink_la_CPPFLAGS) $(CPPFLAGS) $(libkea_asiolink_la_CXXFLAGS) $(CXXFLAGS) -MT libkea_asiolink_la-interval_timer.lo -MD -MP -MF $(DEPDIR)/libkea_asiolink_la-interval_timer.Tpo -c -o libkea_asiolink_la-interval_timer.lo `test -f 'interval_timer.cc' || echo '$(srcdir)/'`interval_timer.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libkea_asiolink_la-interval_timer.Tpo $(DEPDIR)/libkea_asiolink_la-interval_timer.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='interval_timer.cc' object='libkea_asiolink_la-interval_timer.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkea_asiolink_la_CPPFLAGS) $(CPPFLAGS) $(libkea_asiolink_la_CXXFLAGS) $(CXXFLAGS) -c -o libkea_asiolink_la-interval_timer.lo `test -f 'interval_timer.cc' || echo '$(srcdir)/'`interval_timer.cc libkea_asiolink_la-io_address.lo: io_address.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkea_asiolink_la_CPPFLAGS) $(CPPFLAGS) $(libkea_asiolink_la_CXXFLAGS) $(CXXFLAGS) -MT libkea_asiolink_la-io_address.lo -MD -MP -MF $(DEPDIR)/libkea_asiolink_la-io_address.Tpo -c -o libkea_asiolink_la-io_address.lo `test -f 'io_address.cc' || echo '$(srcdir)/'`io_address.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libkea_asiolink_la-io_address.Tpo $(DEPDIR)/libkea_asiolink_la-io_address.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='io_address.cc' object='libkea_asiolink_la-io_address.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkea_asiolink_la_CPPFLAGS) $(CPPFLAGS) $(libkea_asiolink_la_CXXFLAGS) $(CXXFLAGS) -c -o libkea_asiolink_la-io_address.lo `test -f 'io_address.cc' || echo '$(srcdir)/'`io_address.cc libkea_asiolink_la-io_endpoint.lo: io_endpoint.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkea_asiolink_la_CPPFLAGS) $(CPPFLAGS) $(libkea_asiolink_la_CXXFLAGS) $(CXXFLAGS) -MT libkea_asiolink_la-io_endpoint.lo -MD -MP -MF $(DEPDIR)/libkea_asiolink_la-io_endpoint.Tpo -c -o libkea_asiolink_la-io_endpoint.lo `test -f 'io_endpoint.cc' || echo '$(srcdir)/'`io_endpoint.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libkea_asiolink_la-io_endpoint.Tpo $(DEPDIR)/libkea_asiolink_la-io_endpoint.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='io_endpoint.cc' object='libkea_asiolink_la-io_endpoint.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkea_asiolink_la_CPPFLAGS) $(CPPFLAGS) $(libkea_asiolink_la_CXXFLAGS) $(CXXFLAGS) -c -o libkea_asiolink_la-io_endpoint.lo `test -f 'io_endpoint.cc' || echo '$(srcdir)/'`io_endpoint.cc libkea_asiolink_la-io_service.lo: io_service.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkea_asiolink_la_CPPFLAGS) $(CPPFLAGS) $(libkea_asiolink_la_CXXFLAGS) $(CXXFLAGS) -MT libkea_asiolink_la-io_service.lo -MD -MP -MF $(DEPDIR)/libkea_asiolink_la-io_service.Tpo -c -o libkea_asiolink_la-io_service.lo `test -f 'io_service.cc' || echo '$(srcdir)/'`io_service.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libkea_asiolink_la-io_service.Tpo $(DEPDIR)/libkea_asiolink_la-io_service.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='io_service.cc' object='libkea_asiolink_la-io_service.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkea_asiolink_la_CPPFLAGS) $(CPPFLAGS) $(libkea_asiolink_la_CXXFLAGS) $(CXXFLAGS) -c -o libkea_asiolink_la-io_service.lo `test -f 'io_service.cc' || echo '$(srcdir)/'`io_service.cc libkea_asiolink_la-io_socket.lo: io_socket.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkea_asiolink_la_CPPFLAGS) $(CPPFLAGS) $(libkea_asiolink_la_CXXFLAGS) $(CXXFLAGS) -MT libkea_asiolink_la-io_socket.lo -MD -MP -MF $(DEPDIR)/libkea_asiolink_la-io_socket.Tpo -c -o libkea_asiolink_la-io_socket.lo `test -f 'io_socket.cc' || echo '$(srcdir)/'`io_socket.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libkea_asiolink_la-io_socket.Tpo $(DEPDIR)/libkea_asiolink_la-io_socket.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='io_socket.cc' object='libkea_asiolink_la-io_socket.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkea_asiolink_la_CPPFLAGS) $(CPPFLAGS) $(libkea_asiolink_la_CXXFLAGS) $(CXXFLAGS) -c -o libkea_asiolink_la-io_socket.lo `test -f 'io_socket.cc' || echo '$(srcdir)/'`io_socket.cc mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-libkea_asiolink_includeHEADERS: $(libkea_asiolink_include_HEADERS) @$(NORMAL_INSTALL) @list='$(libkea_asiolink_include_HEADERS)'; test -n "$(libkea_asiolink_includedir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(libkea_asiolink_includedir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libkea_asiolink_includedir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(libkea_asiolink_includedir)'"; \ $(INSTALL_HEADER) $$files "$(DESTDIR)$(libkea_asiolink_includedir)" || exit $$?; \ done uninstall-libkea_asiolink_includeHEADERS: @$(NORMAL_UNINSTALL) @list='$(libkea_asiolink_include_HEADERS)'; test -n "$(libkea_asiolink_includedir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(libkea_asiolink_includedir)'; $(am__uninstall_files_from_dir) # This directory's subdirectories are mostly independent; you can cd # into them and run 'make' without going through this Makefile. # To change the values of 'make' variables: instead of editing Makefiles, # (1) if the variable is set in 'config.status', edit 'config.status' # (which will cause the Makefiles to be regenerated when you run 'make'); # (2) otherwise, pass the desired values on the 'make' command line. $(am__recursive_targets): @fail=; \ if $(am__make_keepgoing); then \ failcom='fail=yes'; \ else \ failcom='exit 1'; \ fi; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-recursive CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-recursive cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done check-am: all-am check: check-recursive all-am: Makefile $(LTLIBRARIES) $(HEADERS) installdirs: installdirs-recursive installdirs-am: for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(libkea_asiolink_includedir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-recursive clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ mostlyclean-am distclean: distclean-recursive -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-libkea_asiolink_includeHEADERS install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-libLTLIBRARIES install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: uninstall-libLTLIBRARIES \ uninstall-libkea_asiolink_includeHEADERS .MAKE: $(am__recursive_targets) install-am install-strip .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ check-am clean clean-generic clean-libLTLIBRARIES \ clean-libtool cscopelist-am ctags ctags-am distclean \ distclean-compile distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am \ install-libLTLIBRARIES install-libkea_asiolink_includeHEADERS \ install-man install-pdf install-pdf-am install-ps \ install-ps-am install-strip installcheck installcheck-am \ installdirs installdirs-am maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am uninstall-libLTLIBRARIES \ uninstall-libkea_asiolink_includeHEADERS # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: kea-1.1.0/src/lib/asiolink/interval_timer.h0000664000175000017500000001147112772017075015553 00000000000000// Copyright (C) 2011-2015 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 ASIOLINK_INTERVAL_TIMER_H #define ASIOLINK_INTERVAL_TIMER_H 1 #include #include #include namespace isc { namespace asiolink { class IntervalTimerImpl; /// \brief The \c IntervalTimer class is a wrapper for the ASIO /// \c boost::asio::deadline_timer class. /// /// This class is implemented to use \c boost::asio::deadline_timer as interval /// timer. /// /// \c setup() sets a timer to expire on (now + interval), a call back /// function, and an interval mode. /// /// \c IntervalTimerImpl::callback() is called by the timer when it expires. /// /// The function calls the call back function set by \c setup() and if the /// the interval mode indicates a repeating interval, will reschedule the /// timer to expire in (now + interval) milliseconds. /// /// The type of call back function is \c void(void). /// /// The call back function will not be called if the instance of this class is /// destroyed before the timer is expired. /// /// Sample code: /// \code /// void function_to_call_back() { /// // this function will be called periodically /// } /// int interval_in_milliseconds = 1000; /// IOService io_service; /// /// IntervalTimer intervalTimer(io_service); /// intervalTimer.setup(function_to_call_back, interval_in_milliseconds); /// io_service.run(); /// \endcode class IntervalTimer { public: /// \name The type of timer callback function typedef boost::function Callback; /// \brief Defines possible timer modes used to setup a timer. /// - REPEATING - Timer will reschedule itself after each expiration /// - ONE_SHOT - Timer will expire after one interval and not reschedule. enum Mode { REPEATING, ONE_SHOT }; /// /// \name Constructors and Destructor /// /// Note: The copy constructor and the assignment operator are /// intentionally defined as private, making this class non-copyable. //@{ private: IntervalTimer(const IntervalTimer& source); IntervalTimer& operator=(const IntervalTimer& source); public: /// \brief The constructor with \c IOService. /// /// This constructor may throw a standard exception if /// memory allocation fails inside the method. /// This constructor may also throw \c boost::system::system_error. /// /// \param io_service A reference to an instance of IOService IntervalTimer(IOService& io_service); /// \brief The destructor. /// /// This destructor never throws an exception. /// /// On the destruction of this class the timer will be canceled /// inside \c boost::asio::deadline_timer. ~IntervalTimer(); //@} /// \brief Register timer callback function and interval. /// /// This function sets callback function and interval in milliseconds. /// Timer will actually start after calling \c IOService::run(). /// /// \param cbfunc A reference to a function \c void(void) to call back /// when the timer is expired (should not be an empty functor) /// \param interval Interval in milliseconds (greater than 0) /// \param mode Determines if the timer will automatically reschedule after /// each expiration (the default) or behave as a one-shot which will run /// for a single interval and not reschedule. /// /// Note: IntervalTimer will not pass \c boost::system::error_code to /// call back function. In case the timer is canceled, the function /// will not be called. /// /// \throw isc::InvalidParameter cbfunc is empty /// \throw isc::BadValue interval is less than or equal to 0 /// \throw isc::Unexpected internal runtime error void setup(const Callback& cbfunc, const long interval, const Mode& mode = REPEATING); /// Cancel the timer. /// /// If the timer has been set up, this method cancels any asynchronous /// events waiting on the timer and stops the timer itself. /// If the timer has already been canceled, this method effectively does /// nothing. /// /// This method never throws an exception. void cancel(); /// Return the timer interval. /// /// This method returns the timer interval in milliseconds if it's running; /// if the timer has been canceled it returns 0. /// /// This method never throws an exception. long getInterval() const; private: boost::shared_ptr impl_; }; typedef boost::shared_ptr IntervalTimerPtr; } // namespace asiolink } // namespace isc #endif // ASIOLINK_INTERVAL_TIMER_H kea-1.1.0/src/lib/asiolink/dummy_io_cb.h0000664000175000017500000000472312772017075015017 00000000000000// Copyright (C) 2011-2015 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 DUMMY_IO_CB_H #define DUMMY_IO_CB_H #include #include #include namespace isc { namespace asiolink { /// \brief Asynchronous I/O Completion Callback /// /// The two socket classes (UDPSocket and TCPSocket) require that the I/O /// completion callback function have an operator() method with the appropriate /// signature. The classes are templates, any class with that method and /// signature can be passed as the callback object - there is no need for a /// base class defining the interface. However, some users of the socket /// classes do not use the asynchronous I/O operations, yet have to supply a /// template parameter. This is the reason for this class - it is the dummy /// template parameter. class DummyIOCallback { public: /// \brief Asynchronous I/O callback method /// /// Should never be called, as this class is a convenience class provided /// for instances where a socket is required but it is known that no /// asynchronous operations will be carried out. void operator()(boost::system::error_code) { // If the function is called, there is a serious logic error in // the program (this class should not be used as the callback // class). As the asiolink module is too low-level for logging // errors, throw an exception. isc_throw(isc::Unexpected, "DummyIOCallback::operator() must not be called"); } /// \brief Asynchronous I/O callback method /// /// Should never be called, as this class is a convenience class provided /// for instances where a socket is required but it is known that no /// asynchronous operations will be carried out. void operator()(boost::system::error_code, size_t) { // If the function is called, there is a serious logic error in // the program (this class should not be used as the callback // class). As the asiolink module is too low-level for logging // errors, throw an exception. isc_throw(isc::Unexpected, "DummyIOCallback::operator() must not be called"); } }; } // namespace asiolink } // namespace isc #endif // DUMMY_IO_CB_H kea-1.1.0/src/lib/asiolink/io_endpoint.h0000664000175000017500000001653412772017075015043 00000000000000// Copyright (C) 2010-2015 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 IO_ENDPOINT_H #define IO_ENDPOINT_H 1 // IMPORTANT NOTE: only very few ASIO headers files can be included in // this file. In particular, asio.hpp should never be included here. // See the description of the namespace below. #include #include #include #include # include #include // for some network system calls #include // for sockaddr namespace isc { namespace asiolink { /// \brief The \c IOEndpoint class is an abstract base class to represent /// a communication endpoint. /// /// This class is a wrapper for the ASIO endpoint classes such as /// \c ip::tcp::endpoint and \c ip::udp::endpoint. /// /// Derived class implementations are completely hidden within the /// implementation. User applications only get access to concrete /// \c IOEndpoint objects via the abstract interfaces. class IOEndpoint { /// /// \name Constructors and Destructor /// /// Note: The copy constructor and the assignment operator are /// intentionally defined as private, making this class non-copyable. //@{ private: IOEndpoint(const IOEndpoint& source); IOEndpoint& operator=(const IOEndpoint& source); protected: /// \brief The default constructor. /// /// This is intentionally defined as \c protected as this base class /// should never be instantiated (except as part of a derived class). IOEndpoint() {} public: /// The destructor. virtual ~IOEndpoint() {} //@} /// \brief Returns the address of the endpoint. /// /// This method returns an IOAddress object corresponding to \c this /// endpoint. /// /// Note that the return value is a real object, not a reference or /// a pointer. /// /// This is aligned with the interface of the ASIO counterpart: /// the \c address() method of \c ip::xxx::endpoint classes returns /// an \c ip::address object. /// /// This also means handling the address of an endpoint using this method /// can be expensive. If the address information is necessary in a /// performance sensitive context and there's a more efficient interface /// for that purpose, it's probably better to avoid using this method. /// /// This method never throws an exception. /// /// \return A copy of \c IOAddress object corresponding to the endpoint. virtual IOAddress getAddress() const = 0; /// \brief Returns the port of the endpoint. virtual uint16_t getPort() const = 0; /// \brief Returns the protocol number of the endpoint (TCP, UDP...) virtual short getProtocol() const = 0; /// \brief Returns the address family of the endpoint. virtual short getFamily() const = 0; /// \brief Returns the address of the endpoint in the form of sockaddr /// structure. /// /// The actual instance referenced by the returned value of this method /// is of per address family structure: For IPv4 (AF_INET), it's /// \c sockaddr_in; for IPv6 (AF_INET6), it's \c sockaddr_in6. /// The corresponding port and address members of the underlying structure /// will be set in the network byte order. /// /// This method is "redundant" in that all information to construct the /// \c sockaddr is available via the other "get" methods. /// It is still defined for performance sensitive applications that need /// to get the address information, such as for address based access /// control at a high throughput. Internally it is implemented with /// minimum overhead such as data copy (this is another reason why this /// method returns a reference). /// /// As a tradeoff, this method is more fragile; it assumes that the /// underlying ASIO implementation stores the address information in /// the form of \c sockaddr and it can be accessed in an efficient way. /// This is the case as of this writing, but if the underlying /// implementation changes this method may become much slower or its /// interface may have to be changed, too. /// /// It is therefore discouraged for normal applications to use this /// method. Unless the application is very performance sensitive, it /// should use the other "get" method to retrieve specific information /// of the endpoint. /// /// The returned reference is only valid while the corresponding /// \c IOEndpoint is valid. Once it's destructed the reference will /// become invalid. /// /// \exception None /// \return Reference to a \c sockaddr structure corresponding to the /// endpoint. virtual const struct sockaddr& getSockAddr() const = 0; bool operator==(const IOEndpoint& other) const; bool operator!=(const IOEndpoint& other) const; /// \brief A polymorphic factory of endpoint from address and port. /// /// This method creates a new instance of (a derived class of) /// \c IOEndpoint object that identifies the pair of given address /// and port. /// The appropriate derived class is chosen based on the specified /// transport protocol. If the \c protocol doesn't specify a protocol /// supported in this implementation, an exception of class \c IOError /// will be thrown. /// /// Memory for the created object will be dynamically allocated. It's /// the caller's responsibility to \c delete it later. /// If resource allocation for the new object fails, a corresponding /// standard exception will be thrown. /// /// \param protocol The transport protocol used for the endpoint. /// Currently, only \c IPPROTO_UDP and \c IPPROTO_TCP can be specified. /// \param address The (IP) address of the endpoint. /// \param port The transport port number of the endpoint /// \return A pointer to a newly created \c IOEndpoint object. static const IOEndpoint* create(const int protocol, const IOAddress& address, const unsigned short port); }; /// \brief Insert the \c IOEndpoint as a string into stream. /// /// This method converts \c endpoint into a string and inserts it into the /// output stream \c os. /// /// This method converts the address and port of the endpoint in the textual /// format that other Kea modules would use in logging, i.e., /// - For IPv6 address: [<address>]:port (e.g., [2001:db8::5300]:53) /// - For IPv4 address: <address>:port (e.g., 192.0.2.53:5300) /// /// If it's neither IPv6 nor IPv4, it converts the endpoint into text in the /// same format as that for IPv4, although in practice such a case is not /// really expected. /// /// \param os A \c std::ostream object on which the insertion operation is /// performed. /// \param endpoint A reference to an \c IOEndpoint object output by the /// operation. /// \return A reference to the same \c std::ostream object referenced by /// parameter \c os after the insertion operation. std::ostream& operator<<(std::ostream& os, const IOEndpoint& endpoint); } // namespace asiolink } // namespace isc #endif // IO_ENDPOINT_H // Local Variables: // mode: c++ // End: kea-1.1.0/src/lib/asiolink/asiolink.h0000664000175000017500000000556712772017075014351 00000000000000// Copyright (C) 2010-2015 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 ASIOLINK_H #define ASIOLINK_H 1 // IMPORTANT NOTE: only very few ASIO headers files can be included in // this file. In particular, asio.hpp should never be included here. // See the description of the namespace below. #include #include #include #include #include #include /// \namespace asiolink /// \brief A wrapper interface for the ASIO library. /// /// The \c asiolink namespace is used to define a set of wrapper interfaces /// for the ASIO library. /// /// Kea uses the Boost version of ASIO in its header-only mode, /// i.e., does not require a separate library object to be linked, and thus /// lowers the bar for introduction. /// /// But the advantage comes with its own costs: since the header-only version /// includes more definitions in public header files, it tends to trigger /// more compiler warnings for our own sources, and, depending on the /// compiler options, may make the build fail. /// /// We also found it may be tricky to use ASIO and standard C++ libraries /// in a single translation unit, i.e., a .cc file: depending on the order /// of including header files, ASIO may or may not work on some platforms. /// /// This wrapper interface is intended to centralize these /// problematic issues in a single sub module. Other Kea modules should /// simply include \c asiolink.h and use the wrapper API instead of /// including ASIO header files and using ASIO-specific classes directly. /// /// This wrapper may be used for other IO libraries if and when we want to /// switch, but generality for that purpose is not the primary goal of /// this module. The resulting interfaces are thus straightforward mapping /// to the ASIO counterparts. /// /// One obvious drawback of this approach is performance overhead /// due to the additional layer. We should eventually evaluate the cost /// of the wrapper abstraction in benchmark tests. Another drawback is /// that the wrapper interfaces don't provide all features of ASIO /// (at least for the moment). We should also re-evaluate the /// maintenance overhead of providing necessary wrappers as we develop /// more. /// /// On the other hand, we may be able to exploit the wrapper approach to /// simplify the interfaces (by limiting the usage) and unify performance /// optimization points. /// /// As for optimization, we may want to provide a custom allocator for /// the placeholder of callback handlers: /// http://think-async.com/Asio/asio-1.3.1/doc/asio/reference/asio_handler_allocate.html #endif // ASIOLINK_H kea-1.1.0/src/lib/asiolink/tcp_endpoint.h0000664000175000017500000000714512772017075015220 00000000000000// Copyright (C) 2011-2015 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 TCP_ENDPOINT_H #define TCP_ENDPOINT_H 1 #ifndef BOOST_ASIO_HPP #error "asio.hpp must be included before including this, see asiolink.h as to why" #endif #include namespace isc { namespace asiolink { /// \brief The \c TCPEndpoint class is a concrete derived class of /// \c IOEndpoint that represents an endpoint of a TCP packet. /// /// Other notes about \c TCPEndpoint applies to this class, too. class TCPEndpoint : public IOEndpoint { public: /// /// \name Constructors and Destructor. /// //@{ /// \brief Default Constructor /// /// Creates an internal endpoint. This is expected to be set by some /// external call. TCPEndpoint() : asio_endpoint_placeholder_(new boost::asio::ip::tcp::endpoint()), asio_endpoint_(*asio_endpoint_placeholder_) {} /// \brief Constructor from a pair of address and port. /// /// \param address The IP address of the endpoint. /// \param port The TCP port number of the endpoint. TCPEndpoint(const IOAddress& address, const unsigned short port) : asio_endpoint_placeholder_( new boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string(address.toText()), port)), asio_endpoint_(*asio_endpoint_placeholder_) {} /// \brief Constructor from an ASIO TCP endpoint. /// /// This constructor is designed to be an efficient wrapper for the /// corresponding ASIO class, \c tcp::endpoint. /// /// \param asio_endpoint The ASIO representation of the TCP endpoint. TCPEndpoint(boost::asio::ip::tcp::endpoint& asio_endpoint) : asio_endpoint_placeholder_(NULL), asio_endpoint_(asio_endpoint) {} /// \brief Constructor from an ASIO TCP endpoint. /// /// This constructor is designed to be an efficient wrapper for the /// corresponding ASIO class, \c tcp::endpoint. /// /// \param asio_endpoint The ASIO representation of the TCP endpoint. TCPEndpoint(const boost::asio::ip::tcp::endpoint& asio_endpoint) : asio_endpoint_placeholder_(new boost::asio::ip::tcp::endpoint(asio_endpoint)), asio_endpoint_(*asio_endpoint_placeholder_) {} /// \brief The destructor. virtual ~TCPEndpoint() { delete asio_endpoint_placeholder_; } //@} virtual IOAddress getAddress() const { return (asio_endpoint_.address()); } virtual const struct sockaddr& getSockAddr() const { return (*asio_endpoint_.data()); } virtual uint16_t getPort() const { return (asio_endpoint_.port()); } virtual short getProtocol() const { return (asio_endpoint_.protocol().protocol()); } virtual short getFamily() const { return (asio_endpoint_.protocol().family()); } // This is not part of the exposed IOEndpoint API but allows // direct access to the ASIO implementation of the endpoint inline const boost::asio::ip::tcp::endpoint& getASIOEndpoint() const { return (asio_endpoint_); } inline boost::asio::ip::tcp::endpoint& getASIOEndpoint() { return (asio_endpoint_); } private: boost::asio::ip::tcp::endpoint* asio_endpoint_placeholder_; boost::asio::ip::tcp::endpoint& asio_endpoint_; }; } // namespace asiolink } // namespace isc #endif // TCP_ENDPOINT_H // Local Variables: // mode: c++ // End: kea-1.1.0/src/lib/asiolink/Makefile.am0000664000175000017500000000313012772445242014404 00000000000000SUBDIRS = . tests AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib AM_CPPFLAGS += $(BOOST_INCLUDES) AM_CXXFLAGS = $(KEA_CXXFLAGS) CLEANFILES = *.gcno *.gcda # This is a wrapper library. # The ASIO header files have some code fragments that would hit # gcc's unused-parameter warning, which would make the build fail # with -Werror (our default setting). lib_LTLIBRARIES = libkea-asiolink.la libkea_asiolink_la_LDFLAGS = -no-undefined -version-info 3:0:0 libkea_asiolink_la_SOURCES = asiolink.h libkea_asiolink_la_SOURCES += asio_wrapper.h libkea_asiolink_la_SOURCES += dummy_io_cb.h libkea_asiolink_la_SOURCES += interval_timer.cc interval_timer.h libkea_asiolink_la_SOURCES += io_address.cc io_address.h libkea_asiolink_la_SOURCES += io_asio_socket.h libkea_asiolink_la_SOURCES += io_endpoint.cc io_endpoint.h libkea_asiolink_la_SOURCES += io_error.h libkea_asiolink_la_SOURCES += io_service.h io_service.cc libkea_asiolink_la_SOURCES += io_socket.h io_socket.cc libkea_asiolink_la_SOURCES += tcp_endpoint.h libkea_asiolink_la_SOURCES += tcp_socket.h libkea_asiolink_la_SOURCES += udp_endpoint.h libkea_asiolink_la_SOURCES += udp_socket.h # Note: the ordering matters: -Wno-... must follow -Wextra (defined in # KEA_CXXFLAGS) libkea_asiolink_la_CXXFLAGS = $(AM_CXXFLAGS) libkea_asiolink_la_CPPFLAGS = $(AM_CPPFLAGS) libkea_asiolink_la_LIBADD = $(top_builddir)/src/lib/exceptions/libkea-exceptions.la libkea_asiolink_la_LIBADD += $(BOOST_LIBS) # IOAddress is sometimes used in user-library code libkea_asiolink_includedir = $(pkgincludedir)/asiolink libkea_asiolink_include_HEADERS = io_address.h kea-1.1.0/src/lib/asiolink/tcp_socket.h0000664000175000017500000003514412772017075014670 00000000000000// Copyright (C) 2011-2015 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 TCP_SOCKET_H #define TCP_SOCKET_H 1 #ifndef BOOST_ASIO_HPP #error "asio.hpp must be included before including this, see asiolink.h as to why" #endif #include #include #include // for some IPC/network system calls #include #include #include #include #include #include #include #include #include #include #include namespace isc { namespace asiolink { /// \brief Buffer Too Large /// /// Thrown on an attempt to send a buffer > 64k class BufferTooLarge : public IOError { public: BufferTooLarge(const char* file, size_t line, const char* what) : IOError(file, line, what) {} }; /// \brief The \c TCPSocket class is a concrete derived class of \c IOAsioSocket /// that represents a TCP socket. /// /// \param C Callback type template class TCPSocket : public IOAsioSocket { private: /// \brief Class is non-copyable TCPSocket(const TCPSocket&); TCPSocket& operator=(const TCPSocket&); public: /// \brief Constructor from an ASIO TCP socket. /// /// \param socket The ASIO representation of the TCP socket. It is assumed /// that the caller will open and close the socket, so these /// operations are a no-op for that socket. TCPSocket(boost::asio::ip::tcp::socket& socket); /// \brief Constructor /// /// Used when the TCPSocket is being asked to manage its own internal /// socket. In this case, the open() and close() methods are used. /// /// \param service I/O Service object used to manage the socket. TCPSocket(IOService& service); /// \brief Destructor virtual ~TCPSocket(); /// \brief Return file descriptor of underlying socket virtual int getNative() const { return (socket_.native()); } /// \brief Return protocol of socket virtual int getProtocol() const { return (IPPROTO_TCP); } /// \brief Is "open()" synchronous? /// /// Indicates that the opening of a TCP socket is asynchronous. virtual bool isOpenSynchronous() const { return (false); } /// \brief Open Socket /// /// Opens the TCP socket. This is an asynchronous operation, completion of /// which will be signalled via a call to the callback function. /// /// \param endpoint Endpoint to which the socket will connect. /// \param callback Callback object. virtual void open(const IOEndpoint* endpoint, C& callback); /// \brief Send Asynchronously /// /// Calls the underlying socket's async_send() method to send a packet of /// data asynchronously to the remote endpoint. The callback will be called /// on completion. /// /// \param data Data to send /// \param length Length of data to send /// \param endpoint Target of the send. (Unused for a TCP socket because /// that was determined when the connection was opened.) /// \param callback Callback object. virtual void asyncSend(const void* data, size_t length, const IOEndpoint* endpoint, C& callback); /// \brief Receive Asynchronously /// /// Calls the underlying socket's async_receive() method to read a packet /// of data from a remote endpoint. Arrival of the data is signalled via a /// call to the callback function. /// /// \param data Buffer to receive incoming message /// \param length Length of the data buffer /// \param offset Offset into buffer where data is to be put /// \param endpoint Source of the communication /// \param callback Callback object virtual void asyncReceive(void* data, size_t length, size_t offset, IOEndpoint* endpoint, C& callback); /// \brief Process received data packet /// /// See the description of IOAsioSocket::receiveComplete for a complete /// description of this method. /// /// \param staging Pointer to the start of the staging buffer. /// \param length Amount of data in the staging buffer. /// \param cumulative Amount of data received before the staging buffer is /// processed. /// \param offset Unused. /// \param expected unused. /// \param outbuff Output buffer. Data in the staging buffer is be copied /// to this output buffer in the call. /// /// \return Always true virtual bool processReceivedData(const void* staging, size_t length, size_t& cumulative, size_t& offset, size_t& expected, isc::util::OutputBufferPtr& outbuff); /// \brief Cancel I/O On Socket virtual void cancel(); /// \brief Close socket virtual void close(); private: // Two variables to hold the socket - a socket and a pointer to it. This // handles the case where a socket is passed to the TCPSocket on // construction, or where it is asked to manage its own socket. boost::asio::ip::tcp::socket* socket_ptr_; ///< Pointer to own socket boost::asio::ip::tcp::socket& socket_; ///< Socket bool isopen_; ///< true when socket is open // TODO: Remove temporary buffer // The current implementation copies the buffer passed to asyncSend() into // a temporary buffer and precedes it with a two-byte count field. As // ASIO should really be just about sending and receiving data, the TCP // code should not do this. If the protocol using this requires a two-byte // count, it should add it before calling this code. (This may be best // achieved by altering isc::dns::buffer to have pairs of methods: // getLength()/getTCPLength(), getData()/getTCPData(), with the getTCPXxx() // methods taking into account a two-byte count field.) // // The option of sending the data in two operations, the count followed by // the data was discounted as that would lead to two callbacks which would // cause problems with the stackless coroutine code. isc::util::OutputBufferPtr send_buffer_; ///< Send buffer }; // Constructor - caller manages socket template TCPSocket::TCPSocket(boost::asio::ip::tcp::socket& socket) : socket_ptr_(NULL), socket_(socket), isopen_(true), send_buffer_() { } // Constructor - create socket on the fly template TCPSocket::TCPSocket(IOService& service) : socket_ptr_(new boost::asio::ip::tcp::socket(service.get_io_service())), socket_(*socket_ptr_), isopen_(false) { } // Destructor. Only delete the socket if we are managing it. template TCPSocket::~TCPSocket() { delete socket_ptr_; } // Open the socket. template void TCPSocket::open(const IOEndpoint* endpoint, C& callback) { // Ignore opens on already-open socket. Don't throw a failure because // of uncertainties as to what precedes whan when using asynchronous I/O. // At also allows us a treat a passed-in socket as a self-managed socket. if (!isopen_) { if (endpoint->getFamily() == AF_INET) { socket_.open(boost::asio::ip::tcp::v4()); } else { socket_.open(boost::asio::ip::tcp::v6()); } isopen_ = true; // Set options on the socket: // Reuse address - allow the socket to bind to a port even if the port // is in the TIMED_WAIT state. socket_.set_option(boost::asio::socket_base::reuse_address(true)); } // Upconvert to a TCPEndpoint. We need to do this because although // IOEndpoint is the base class of UDPEndpoint and TCPEndpoint, it does not // contain a method for getting at the underlying endpoint type - that is in /// the derived class and the two classes differ on return type. assert(endpoint->getProtocol() == IPPROTO_TCP); const TCPEndpoint* tcp_endpoint = static_cast(endpoint); // Connect to the remote endpoint. On success, the handler will be // called (with one argument - the length argument will default to // zero). socket_.async_connect(tcp_endpoint->getASIOEndpoint(), callback); } // Send a message. Should never do this if the socket is not open, so throw // an exception if this is the case. template void TCPSocket::asyncSend(const void* data, size_t length, const IOEndpoint*, C& callback) { if (isopen_) { // Need to copy the data into a temporary buffer and precede it with // a two-byte count field. // TODO: arrange for the buffer passed to be preceded by the count try { // Ensure it fits into 16 bits uint16_t count = boost::numeric_cast(length); // Copy data into a buffer preceded by the count field. send_buffer_.reset(new isc::util::OutputBuffer(length + 2)); send_buffer_->writeUint16(count); send_buffer_->writeData(data, length); // ... and send it socket_.async_send(boost::asio::buffer(send_buffer_->getData(), send_buffer_->getLength()), callback); } catch (boost::numeric::bad_numeric_cast&) { isc_throw(BufferTooLarge, "attempt to send buffer larger than 64kB"); } } else { isc_throw(SocketNotOpen, "attempt to send on a TCP socket that is not open"); } } // Receive a message. Note that the "offset" argument is used as an index // into the buffer in order to decide where to put the data. It is up to the // caller to initialize the data to zero template void TCPSocket::asyncReceive(void* data, size_t length, size_t offset, IOEndpoint* endpoint, C& callback) { if (isopen_) { // Upconvert to a TCPEndpoint. We need to do this because although // IOEndpoint is the base class of UDPEndpoint and TCPEndpoint, it // does not contain a method for getting at the underlying endpoint // type - that is in the derived class and the two classes differ on // return type. assert(endpoint->getProtocol() == IPPROTO_TCP); TCPEndpoint* tcp_endpoint = static_cast(endpoint); // Write the endpoint details from the communications link. Ideally // we should make IOEndpoint assignable, but this runs in to all sorts // of problems concerning the management of the underlying Boost // endpoint (e.g. if it is not self-managed, is the copied one // self-managed?) The most pragmatic solution is to let Boost take care // of everything and copy details of the underlying endpoint. tcp_endpoint->getASIOEndpoint() = socket_.remote_endpoint(); // Ensure we can write into the buffer and if so, set the pointer to // where the data will be written. if (offset >= length) { isc_throw(BufferOverflow, "attempt to read into area beyond end of " "TCP receive buffer"); } void* buffer_start = static_cast(static_cast(data) + offset); // ... and kick off the read. socket_.async_receive(boost::asio::buffer(buffer_start, length - offset), callback); } else { isc_throw(SocketNotOpen, "attempt to receive from a TCP socket that is not open"); } } // Is the receive complete? template bool TCPSocket::processReceivedData(const void* staging, size_t length, size_t& cumulative, size_t& offset, size_t& expected, isc::util::OutputBufferPtr& outbuff) { // Point to the data in the staging buffer and note how much there is. const uint8_t* data = static_cast(staging); size_t data_length = length; // Is the number is "expected" valid? It won't be unless we have received // at least two bytes of data in total for this set of receives. if (cumulative < 2) { // "expected" is not valid. Did this read give us enough data to // work it out? cumulative += length; if (cumulative < 2) { // Nope, still not valid. This must have been the first packet and // was only one byte long. Tell the fetch code to read the next // packet into the staging buffer beyond the data that is already // there so that the next time we are called we have a complete // TCP count. offset = cumulative; return (false); } // Have enough data to interpret the packet count, so do so now. expected = isc::util::readUint16(data, cumulative); // We have two bytes less of data to process. Point to the start of the // data and adjust the packet size. Note that at this point, // "cumulative" is the true amount of data in the staging buffer, not // "length". data += 2; data_length = cumulative - 2; } else { // Update total amount of data received. cumulative += length; } // Regardless of anything else, the next read goes into the start of the // staging buffer. offset = 0; // Work out how much data we still have to put in the output buffer. (This // could be zero if we have just interpreted the TCP count and that was // set to zero.) if (expected >= outbuff->getLength()) { // Still need data in the output packet. Copy what we can from the // staging buffer to the output buffer. size_t copy_amount = std::min(expected - outbuff->getLength(), data_length); outbuff->writeData(data, copy_amount); } // We can now say if we have all the data. return (expected == outbuff->getLength()); } // Cancel I/O on the socket. No-op if the socket is not open. template void TCPSocket::cancel() { if (isopen_) { socket_.cancel(); } } // Close the socket down. Can only do this if the socket is open and we are // managing it ourself. template void TCPSocket::close() { if (isopen_ && socket_ptr_) { socket_.close(); isopen_ = false; } } } // namespace asiolink } // namespace isc #endif // TCP_SOCKET_H kea-1.1.0/src/lib/asiolink/io_address.cc0000664000175000017500000001166012772445242015002 00000000000000// Copyright (C) 2010-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 #include #include #include #include #include #include // for some IPC/network system calls #include #include #include using namespace boost::asio; using boost::asio::ip::udp; using boost::asio::ip::tcp; using namespace std; namespace isc { namespace asiolink { // XXX: we cannot simply construct the address in the initialization list, // because we'd like to throw our own exception on failure. IOAddress::IOAddress(const std::string& address_str) { boost::system::error_code err; asio_address_ = ip::address::from_string(address_str, err); if (err) { isc_throw(IOError, "Failed to convert string to address '" << address_str << "': " << err.message()); } } IOAddress::IOAddress(const boost::asio::ip::address& asio_address) : asio_address_(asio_address) {} IOAddress::IOAddress(uint32_t v4address): asio_address_(boost::asio::ip::address_v4(v4address)) { } string IOAddress::toText() const { return (asio_address_.to_string()); } IOAddress IOAddress::fromBytes(short family, const uint8_t* data) { if (data == NULL) { isc_throw(BadValue, "NULL pointer received."); } else if ( (family != AF_INET) && (family != AF_INET6) ) { isc_throw(BadValue, "Invalid family type. Only AF_INET and AF_INET6" << "are supported"); } BOOST_STATIC_ASSERT(INET6_ADDRSTRLEN >= INET_ADDRSTRLEN); char addr_str[INET6_ADDRSTRLEN]; inet_ntop(family, data, addr_str, INET6_ADDRSTRLEN); return IOAddress(string(addr_str)); } std::vector IOAddress::toBytes() const { if (asio_address_.is_v4()) { const boost::asio::ip::address_v4::bytes_type bytes4 = asio_address_.to_v4().to_bytes(); return (std::vector(bytes4.begin(), bytes4.end())); } // Not V4 address, so must be a V6 address (else we could never construct // this object). const boost::asio::ip::address_v6::bytes_type bytes6 = asio_address_.to_v6().to_bytes(); return (std::vector(bytes6.begin(), bytes6.end())); } short IOAddress::getFamily() const { if (asio_address_.is_v4()) { return (AF_INET); } else { return (AF_INET6); } } bool IOAddress::isV6LinkLocal() const { if (!asio_address_.is_v6()) { return (false); } return (asio_address_.to_v6().is_link_local()); } bool IOAddress::isV6Multicast() const { if (!asio_address_.is_v6()) { return (false); } return (asio_address_.to_v6().is_multicast()); } uint32_t IOAddress::toUint32() const { if (asio_address_.is_v4()) { return (asio_address_.to_v4().to_ulong()); } else { isc_throw(BadValue, "Can't convert " << toText() << " address to IPv4."); } } std::ostream& operator<<(std::ostream& os, const IOAddress& address) { os << address.toText(); return (os); } IOAddress IOAddress::subtract(const IOAddress& a, const IOAddress& b) { if (a.getFamily() != b.getFamily()) { isc_throw(BadValue, "Both addresses have to be the same family"); } if (a.isV4()) { // Subtracting v4 is easy. We have a conversion function to uint32_t. return (IOAddress(a.toUint32() - b.toUint32())); } else { // v6 is more involved. // Let's extract the raw data first. vector a_vec = a.toBytes(); vector b_vec = b.toBytes(); // ... and prepare the result vector result(V6ADDRESS_LEN,0); // Carry is a boolean, but to avoid its frequent casting, let's // use uint8_t. Also, some would prefer to call it borrow, but I prefer // carry. Somewhat relevant discussion here: // http://en.wikipedia.org/wiki/Carry_flag#Carry_flag_vs._Borrow_flag uint8_t carry = 0; // Now perform subtraction with borrow. for (int i = a_vec.size() - 1; i >= 0; --i) { result[i] = a_vec[i] - b_vec[i] - carry; carry = (a_vec[i] < b_vec[i] + carry); } return (fromBytes(AF_INET6, &result[0])); } } IOAddress IOAddress::increase(const IOAddress& addr) { std::vector packed(addr.toBytes()); // Start increasing the least significant byte for (int i = packed.size() - 1; i >= 0; --i) { // if we haven't overflowed (0xff -> 0x0), than we are done if (++packed[i] != 0) { break; } } return (IOAddress::fromBytes(addr.getFamily(), &packed[0])); } } // namespace asiolink } // namespace isc kea-1.1.0/src/lib/asiolink/udp_endpoint.h0000664000175000017500000000714512772017075015222 00000000000000// Copyright (C) 2011-2015 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 UDP_ENDPOINT_H #define UDP_ENDPOINT_H 1 #ifndef BOOST_ASIO_HPP #error "asio.hpp must be included before including this, see asiolink.h as to why" #endif #include namespace isc { namespace asiolink { /// \brief The \c UDPEndpoint class is a concrete derived class of /// \c IOEndpoint that represents an endpoint of a UDP packet. /// /// Other notes about \c TCPEndpoint applies to this class, too. class UDPEndpoint : public IOEndpoint { public: /// /// \name Constructors and Destructor. /// //@{ /// \brief Default Constructor /// /// Creates an internal endpoint. This is expected to be set by some /// external call. UDPEndpoint() : asio_endpoint_placeholder_(new boost::asio::ip::udp::endpoint()), asio_endpoint_(*asio_endpoint_placeholder_) {} /// \brief Constructor from a pair of address and port. /// /// \param address The IP address of the endpoint. /// \param port The UDP port number of the endpoint. UDPEndpoint(const IOAddress& address, const unsigned short port) : asio_endpoint_placeholder_( new boost::asio::ip::udp::endpoint(boost::asio::ip::address::from_string(address.toText()), port)), asio_endpoint_(*asio_endpoint_placeholder_) {} /// \brief Constructor from an ASIO UDP endpoint. /// /// This constructor is designed to be an efficient wrapper for the /// corresponding ASIO class, \c udp::endpoint. /// /// \param asio_endpoint The ASIO representation of the UDP endpoint. UDPEndpoint(boost::asio::ip::udp::endpoint& asio_endpoint) : asio_endpoint_placeholder_(NULL), asio_endpoint_(asio_endpoint) {} /// \brief Constructor from an ASIO UDP endpoint. /// /// This constructor is designed to be an efficient wrapper for the /// corresponding ASIO class, \c udp::endpoint. /// /// \param asio_endpoint The ASIO representation of the TCP endpoint. UDPEndpoint(const boost::asio::ip::udp::endpoint& asio_endpoint) : asio_endpoint_placeholder_(new boost::asio::ip::udp::endpoint(asio_endpoint)), asio_endpoint_(*asio_endpoint_placeholder_) {} /// \brief The destructor. virtual ~UDPEndpoint() { delete asio_endpoint_placeholder_; } //@} virtual IOAddress getAddress() const { return (asio_endpoint_.address()); } virtual const struct sockaddr& getSockAddr() const { return (*asio_endpoint_.data()); } virtual uint16_t getPort() const { return (asio_endpoint_.port()); } virtual short getProtocol() const { return (asio_endpoint_.protocol().protocol()); } virtual short getFamily() const { return (asio_endpoint_.protocol().family()); } // This is not part of the exposed IOEndpoint API but allows // direct access to the ASIO implementation of the endpoint inline const boost::asio::ip::udp::endpoint& getASIOEndpoint() const { return (asio_endpoint_); } inline boost::asio::ip::udp::endpoint& getASIOEndpoint() { return (asio_endpoint_); } private: boost::asio::ip::udp::endpoint* asio_endpoint_placeholder_; boost::asio::ip::udp::endpoint& asio_endpoint_; }; } // namespace asiolink } // namespace isc #endif // UDP_ENDPOINT_H // Local Variables: // mode: c++ // End: kea-1.1.0/src/lib/asiolink/asio_wrapper.h0000664000175000017500000000527412772017075015226 00000000000000// 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 ASIO_WRAPPER_H #define ASIO_WRAPPER_H 1 // !!! IMPORTANT !!!! // This file must be included anywhere one would normally have included // boost/asio.hpp. Until the issue described below is resolved in some // other fashion asio.hpp should not be included other than through // this file. // // The optimizer as of gcc 5.2.0, may not reliably ensure a single value // returned by boost::system::system_category() within a translation unit // when building the header only version of the boost error handling. // See Trac #4243 for more details. For now we turn off optimization for // header only builds the under the suspect GCC versions. // // The issue arises from in-lining the above function, which returns a // reference to a local static variable, system_category_const. This leads // to situations where a construct such as the following: // // {{{ // if (ec == boost::asio::error::would_block // || ec == boost::asio::error::try_again) // return false; // }}} // // which involve implicit conversion of enumerates to error_code instances // to not evaluate correctly. During the implicit conversion the error_code // instances may be assigned differeing values error_code:m_cat. This // causes two instances of error_code which should have been equal to // to not be equal. // // The problem disappers if either error handling code is not built header // only as this results in a single definiton of system_category() supplied // by libboost_system; or the error handling code is not optimized. // // We're doing the test here, rather than in configure to guard against the // user supplying the header only flag via environment variables. // // We opened bugs with GNU and BOOST: // // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69789 // https://svn.boost.org/trac/boost/ticket/11989 // // @todo Version 6.0 will need to be tested. // // As of 2016-08-19, the version 5.4.0 from Ubuntu 16.04 is affected. Updated // the check to cover everything that is not 6.0, hoping that 6.0 solves the // problem. #define GNU_CC_VERSION (__GNUC__ * 10000 \ + __GNUC_MINOR__ * 100 \ + __GNUC_PATCHLEVEL__) #if (defined(__GNUC__) && \ ((GNU_CC_VERSION >= 50200) && (GNU_CC_VERSION < 60000)) \ && defined(BOOST_ERROR_CODE_HEADER_ONLY)) #pragma GCC push_options #pragma GCC optimize ("O0") #include #pragma GCC pop_options #else #include #endif #endif // ASIO_WRAPPER_H kea-1.1.0/src/lib/asiolink/README0000664000175000017500000000213112772017075013227 00000000000000The asiolink library is intended to provide an abstraction layer between Kea modules and the socket I/O subsystem we are using (currently, the headers-only version of ASIO included in Boost). This has several benefits, including: - Simple interface - Back-end flexibility: It would be relatively easy to switch to any other asynchronous I/O system. - Cleaner compilation: The ASIO headers include code which can generate warnings in some compilers due to unused parameters and such. Including ASIO header files throughout the Kea tree would require us to relax the strictness of our error checking. Including them in only one place allows us to relax strictness here, while leaving it in place elsewhere. Some of the classes defined here--for example, IOSocket, IOEndpoint, and IOAddress--are to be used by Kea modules as wrappers around ASIO-specific classes. Logging ------- At this point, nothing is logged by this low-level library. We may revisit that in the future, if we find suitable messages to log, but right now there are also no loggers initialized or called. kea-1.1.0/src/lib/asiolink/io_service.cc0000664000175000017500000000653712772017075015023 00000000000000// Copyright (C) 2011-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 #include #include #include // for some IPC/network system calls #include #include namespace isc { namespace asiolink { namespace { // A trivial wrapper for boost::function. SunStudio doesn't seem to be capable // of handling a boost::function object if directly passed to // io_service::post(). class CallbackWrapper { public: CallbackWrapper(const boost::function& callback) : callback_(callback) {} void operator()() { callback_(); } private: boost::function callback_; }; } class IOServiceImpl { private: IOServiceImpl(const IOService& source); IOServiceImpl& operator=(const IOService& source); public: /// \brief The constructor IOServiceImpl() : io_service_(), work_(io_service_) {}; /// \brief The destructor. ~IOServiceImpl() {}; //@} /// \brief Start the underlying event loop. /// /// This method does not return control to the caller until /// the \c stop() method is called via some handler. void run() { io_service_.run(); }; /// \brief Run the underlying event loop for a single event. /// /// This method return control to the caller as soon as the /// first handler has completed. (If no handlers are ready when /// it is run, it will block until one is.) void run_one() { io_service_.run_one(); }; /// \brief Run the underlying event loop for a ready events. /// /// This method executes handlers for all ready events and returns. /// It will return immediately if there are no ready events. void poll() { io_service_.poll(); }; /// \brief Stop the underlying event loop. /// /// This will return the control to the caller of the \c run() method. void stop() { io_service_.stop();} ; /// \brief Return the native \c io_service object used in this wrapper. /// /// This is a short term work around to support other Kea modules /// that share the same \c io_service with the authoritative server. /// It will eventually be removed once the wrapper interface is /// generalized. boost::asio::io_service& get_io_service() { return io_service_; }; void post(const boost::function& callback) { const CallbackWrapper wrapper(callback); io_service_.post(wrapper); } private: boost::asio::io_service io_service_; boost::asio::io_service::work work_; }; IOService::IOService() { io_impl_ = new IOServiceImpl(); } IOService::~IOService() { delete io_impl_; } void IOService::run() { io_impl_->run(); } void IOService::run_one() { io_impl_->run_one(); } void IOService::poll() { io_impl_->poll(); } void IOService::stop() { io_impl_->stop(); } boost::asio::io_service& IOService::get_io_service() { return (io_impl_->get_io_service()); } void IOService::post(const boost::function& callback) { return (io_impl_->post(callback)); } } // namespace asiolink } // namespace isc kea-1.1.0/src/lib/asiolink/interval_timer.cc0000664000175000017500000001166112772017075015712 00000000000000// Copyright (C) 2011-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 #include #include #include #include #include #include #include namespace isc { namespace asiolink { /// This class holds a call back function of asynchronous operations. /// To ensure the object is alive while an asynchronous operation refers /// to it, we use shared_ptr and enable_shared_from_this. /// The object will be destructed in case IntervalTimer has been destructed /// and no asynchronous operation refers to it. /// Please follow the link to get an example: /// http://think-async.com/asio/asio-1.4.8/doc/asio/tutorial/tutdaytime3.html#asio.tutorial.tutdaytime3.the_tcp_connection_class class IntervalTimerImpl : public boost::enable_shared_from_this { private: // prohibit copy IntervalTimerImpl(const IntervalTimerImpl& source); IntervalTimerImpl& operator=(const IntervalTimerImpl& source); public: IntervalTimerImpl(IOService& io_service); ~IntervalTimerImpl(); void setup(const IntervalTimer::Callback& cbfunc, const long interval, const IntervalTimer::Mode& interval_mode = IntervalTimer::REPEATING); void callback(const boost::system::error_code& error); void cancel() { timer_.cancel(); interval_ = 0; } long getInterval() const { return (interval_); } private: // a function to update timer_ when it expires void update(); // a function to call back when timer_ expires IntervalTimer::Callback cbfunc_; // interval in milliseconds long interval_; // asio timer boost::asio::deadline_timer timer_; // Controls how the timer behaves after expiration. IntervalTimer::Mode mode_; // interval_ will be set to this value in destructor in order to detect // use-after-free type of bugs. static const long INVALIDATED_INTERVAL = -1; }; IntervalTimerImpl::IntervalTimerImpl(IOService& io_service) : interval_(0), timer_(io_service.get_io_service()), mode_(IntervalTimer::REPEATING) {} IntervalTimerImpl::~IntervalTimerImpl() { interval_ = INVALIDATED_INTERVAL; } void IntervalTimerImpl::setup(const IntervalTimer::Callback& cbfunc, const long interval, const IntervalTimer::Mode& mode) { // Interval should not be less than or equal to 0. if (interval <= 0) { isc_throw(isc::BadValue, "Interval should not be less than or " "equal to 0"); } // Call back function should not be empty. if (cbfunc.empty()) { isc_throw(isc::InvalidParameter, "Callback function is empty"); } cbfunc_ = cbfunc; interval_ = interval; mode_ = mode; // Set initial expire time. // At this point the timer is not running yet and will not expire. // After calling IOService::run(), the timer will expire. update(); } void IntervalTimerImpl::update() { try { // Update expire time to (current time + interval_). timer_.expires_from_now(boost::posix_time::millisec(interval_)); // Reset timer. // Pass a function bound with a shared_ptr to this. timer_.async_wait(boost::bind(&IntervalTimerImpl::callback, shared_from_this(), boost::asio::placeholders::error)); } catch (const boost::system::system_error& e) { isc_throw(isc::Unexpected, "Failed to update timer: " << e.what()); } catch (const boost::bad_weak_ptr&) { // Can't happen. It means a severe internal bug. assert(0); } } void IntervalTimerImpl::callback(const boost::system::error_code& ec) { assert(interval_ != INVALIDATED_INTERVAL); if (interval_ == 0 || ec) { // timer has been canceled. Do nothing. } else { // If we should repeat, set next expire time. if (mode_ == IntervalTimer::REPEATING) { update(); } // Invoke the call back function. cbfunc_(); } } IntervalTimer::IntervalTimer(IOService& io_service) : impl_(new IntervalTimerImpl(io_service)) {} IntervalTimer::~IntervalTimer() { // Cancel the timer to make sure cbfunc_() will not be called any more. cancel(); } void IntervalTimer::setup(const Callback& cbfunc, const long interval, const IntervalTimer::Mode& mode) { return (impl_->setup(cbfunc, interval, mode)); } void IntervalTimer::cancel() { impl_->cancel(); } long IntervalTimer::getInterval() const { return (impl_->getInterval()); } } // namespace asiolink } // namespace isc kea-1.1.0/src/lib/asiolink/io_address.h0000664000175000017500000002651212772445242014646 00000000000000// Copyright (C) 2010-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 IO_ADDRESS_H #define IO_ADDRESS_H 1 // IMPORTANT NOTE: only very few ASIO headers files can be included in // this file. In particular, asio.hpp should never be included here. // See the description of the namespace below. #include // for some network system calls #include // for uint32_t #include #include #include #include #include namespace isc { namespace asiolink { /// Defines length of IPv6 address. const static size_t V6ADDRESS_LEN = 16; /// Defines length of IPv4 address. const static size_t V4ADDRESS_LEN = 4; /// \brief The \c IOAddress class represents an IP addresses (version /// agnostic) /// /// This class is a wrapper for the ASIO \c ip::address class. class IOAddress { public: /// /// \name Constructors and Destructor /// /// This class is copyable. We use default versions of copy constructor /// and the assignment operator. /// We use the default destructor. //@{ /// \brief Constructor from string. /// /// This constructor converts a textual representation of IPv4 and IPv6 /// addresses into an IOAddress object. /// If \c address_str is not a valid representation of any type of /// address, an exception of class \c IOError will be thrown. /// This constructor allocates memory for the object, and if that fails /// a corresponding standard exception will be thrown. /// /// \param address_str Textual representation of address. IOAddress(const std::string& address_str); /// \brief Constructor from an ASIO \c ip::address object. /// /// This constructor is intended to be used within the wrapper /// implementation; user applications of the wrapper API won't use it. /// /// This constructor never throws an exception. /// /// \param asio_address The ASIO \c ip::address to be converted. IOAddress(const boost::asio::ip::address& asio_address); //@} /// @brief Constructor for ip::address_v4 object. /// /// This constructor is intented to be used when constructing /// IPv4 address out of uint32_t type. Passed value must be in /// network byte order /// /// @param v4address IPv4 address represnted by uint32_t IOAddress(uint32_t v4address); /// \brief Convert the address to a string. /// /// This method is basically expected to be exception free, but /// generating the string will involve resource allocation, /// and if it fails the corresponding standard exception will be thrown. /// /// \return A string representation of the address. std::string toText() const; /// \brief Returns the address family /// /// \return AF_INET for IPv4 or AF_INET6 for IPv6. short getFamily() const; /// \brief Convenience function to check for an IPv4 address /// /// \return true if the address is a V4 address bool isV4() const { return (asio_address_.is_v4()); } /// \brief Convenience function to check if it is an IPv4 zero address. /// /// \return true if the address is the zero IPv4 address. bool isV4Zero() const { return (equals(IPV4_ZERO_ADDRESS())); } /// \brief Convenience function to check if it is an IPv4 broadcast /// address. /// /// \return true if the address is the broadcast IPv4 address. bool isV4Bcast() const { return (equals(IPV4_BCAST_ADDRESS())); } /// \brief Convenience function to check for an IPv6 address /// /// \return true if the address is a V6 address bool isV6() const { return (asio_address_.is_v6()); } /// \brief Convenience function to check if it is an IPv4 zero address. /// /// \return true if the address is the zero IPv4 address. bool isV6Zero() const { return (equals(IPV6_ZERO_ADDRESS())); } /// \brief checks whether and address is IPv6 and is link-local /// /// \return true if the address is IPv6 link-local, false otherwise bool isV6LinkLocal() const; /// \brief checks whether and address is IPv6 and is multicast /// /// \return true if the address is IPv6 multicast, false otherwise bool isV6Multicast() const; /// \brief Creates an address from over wire data. /// /// \param family AF_NET for IPv4 or AF_NET6 for IPv6. /// \param data pointer to first char of data /// /// \return Created IOAddress object static IOAddress fromBytes(short family, const uint8_t* data); /// \brief Return address as set of bytes /// /// \return Contents of the address as a set of bytes in network-byte /// order. std::vector toBytes() const; /// \brief Compare addresses for equality /// /// \param other Address to compare against. /// /// \return true if addresses are equal, false if not. bool equals(const IOAddress& other) const { return (asio_address_ == other.asio_address_); } /// \brief Compare addresses for equality /// /// \param other Address to compare against. /// /// \return true if addresses are equal, false if not. bool operator==(const IOAddress& other) const { return equals(other); } /// \brief Compare addresses for inequality /// /// \param other Address to compare against. /// /// \return false if addresses are equal, true if not. bool nequals(const IOAddress& other) const { return (!equals(other)); } /// \brief Checks if one address is smaller than the other /// /// \param other Address to compare against. /// /// \return true if this address is smaller than the other address. /// /// It is useful for comparing which address is bigger. /// Operations within one protocol family are obvious. /// Comparisons between v4 and v6 will allways return v4 /// being smaller. This follows boost::boost::asio::ip implementation bool lessThan(const IOAddress& other) const { if (this->getFamily() == other.getFamily()) { if (this->getFamily() == AF_INET6) { return (this->asio_address_.to_v6() < other.asio_address_.to_v6()); } else { return (this->asio_address_.to_v4() < other.asio_address_.to_v4()); } } return (this->getFamily() < other.getFamily()); } /// \brief Checks if one address is smaller or equal than the other /// /// \param other Address to compare against. /// /// \return true if this address is smaller than the other address. bool smallerEqual(const IOAddress& other) const { if (equals(other)) { return (true); } return (lessThan(other)); } /// \brief Checks if one address is smaller than the other /// /// \param other Address to compare against. /// /// See \ref lessThan method for details. bool operator<(const IOAddress& other) const { return (lessThan(other)); } /// \brief Checks if one address is smaller or equal than the other /// /// \param other Address to compare against. /// /// See \ref smallerEqual method for details. bool operator<=(const IOAddress& other) const { return (smallerEqual(other)); } /// \brief Compare addresses for inequality /// /// \param other Address to compare against. /// /// \return false if addresses are equal, true if not. bool operator!=(const IOAddress& other) const { return (nequals(other)); } /// @brief Subtracts one address from another (a - b) /// /// Treats addresses as integers and subtracts them. For example: /// @code /// 192.0.2.5 - 192.0.2.0 = 0.0.0.5 /// fe80::abcd - fe80:: = ::abcd /// @endcode /// /// It is possible to subtract greater from lesser address, e.g. /// 192.168.56.10 - 192.168.67.20, but please do understand that /// the address space is a finite field in mathematical sense, so /// you may end up with a result that is greater then any of the /// addresses you specified. Also, subtraction is not commutative, /// so a - b != b - a. /// /// This operation is essential for calculating the number of /// leases in a pool, where we need to calculate (max - min). /// @throw BadValue if addresses are of different family /// @param a address to be subtracted from /// @param b address to be subtracted /// @return IOAddress object that represents the difference static IOAddress subtract(const IOAddress& a, const IOAddress& b); /// @brief Returns an address increased by one /// /// This method works for both IPv4 and IPv6 addresses. For example, /// increase 192.0.2.255 will become 192.0.3.0. /// /// Address space is a finite field in the mathematical sense, so keep /// in mind that the address space "loops". 255.255.255.255 increased /// by one gives 0.0.0.0. The same is true for maximum value of IPv6 /// (all 1's) looping to ::. /// /// @todo Determine if we have a use-case for increasing the address /// by more than one. Increase by one is used in AllocEngine. This method /// could take extra parameter that specifies the value by which the /// address should be increased. /// /// @param addr address to be increased /// @return address increased by one static IOAddress increase(const IOAddress& addr); /// \brief Converts IPv4 address to uint32_t /// /// Will throw BadValue exception if that is not IPv4 /// address. /// /// \return uint32_t that represents IPv4 address in /// network byte order uint32_t toUint32() const; /// @name Methods returning @c IOAddress objects encapsulating typical addresses. /// //@{ /// @brief Returns an address set to all zeros. static const IOAddress& IPV4_ZERO_ADDRESS() { static IOAddress address(0); return (address); } /// @brief Returns a "255.255.255.255" broadcast address. static const IOAddress& IPV4_BCAST_ADDRESS() { static IOAddress address(0xFFFFFFFF); return (address); } /// @brief Returns an IPv6 zero address. static const IOAddress& IPV6_ZERO_ADDRESS() { static IOAddress address("::"); return (address); } //@} private: boost::asio::ip::address asio_address_; }; /// \brief Insert the IOAddress as a string into stream. /// /// This method converts the \c address into a string and inserts it /// into the output stream \c os. /// /// This function overloads the global operator<< to behave as described /// in ostream::operator<< but applied to \c IOAddress objects. /// /// \param os A \c std::ostream object on which the insertion operation is /// performed. /// \param address The \c IOAddress object output by the operation. /// \return A reference to the same \c std::ostream object referenced by /// parameter \c os after the insertion operation. std::ostream& operator<<(std::ostream& os, const IOAddress& address); } // namespace asiolink } // namespace isc #endif // IO_ADDRESS_H kea-1.1.0/src/lib/asiolink/io_service.h0000664000175000017500000000565112772017075014661 00000000000000// Copyright (C) 2011-2015 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 ASIOLINK_IO_SERVICE_H #define ASIOLINK_IO_SERVICE_H 1 #include namespace boost { namespace asio { class io_service; } } namespace isc { namespace asiolink { class IOServiceImpl; /// \brief The \c IOService class is a wrapper for the ASIO \c io_service /// class. /// class IOService { /// /// \name Constructors and Destructor /// /// Note: The copy constructor and the assignment operator are /// intentionally defined as private, making this class non-copyable. //@{ private: IOService(const IOService& source); IOService& operator=(const IOService& source); public: /// \brief The constructor IOService(); /// \brief The destructor. ~IOService(); //@} /// \brief Start the underlying event loop. /// /// This method does not return control to the caller until /// the \c stop() method is called via some handler. void run(); /// \brief Run the underlying event loop for a single event. /// /// This method return control to the caller as soon as the /// first handler has completed. (If no handlers are ready when /// it is run, it will block until one is.) void run_one(); /// \brief Run the underlying event loop for a ready events. /// /// This method executes handlers for all ready events and returns. /// It will return immediately if there are no ready events. void poll(); /// \brief Stop the underlying event loop. /// /// This will return the control to the caller of the \c run() method. void stop(); /// \brief Return the native \c io_service object used in this wrapper. /// /// This is a short term work around to support other Kea modules /// that share the same \c io_service with the authoritative server. /// It will eventually be removed once the wrapper interface is /// generalized. boost::asio::io_service& get_io_service(); /// \brief Post a callback to the end of the queue. /// /// Requests the callback be called sometime later. It is not guaranteed /// by the underlying asio, but it can reasonably be expected the callback /// is put to the end of the callback queue. It is not called from within /// this function. /// /// It may be used to implement "background" work, for example (doing stuff /// by small bits that are called from time to time). void post(const boost::function& callback); private: IOServiceImpl* io_impl_; }; /// @brief Defines a smart pointer to an IOService instance. typedef boost::shared_ptr IOServicePtr; } // namespace asiolink } // namespace isc #endif // ASIOLINK_IO_SERVICE_H kea-1.1.0/src/lib/asiolink/udp_socket.h0000664000175000017500000002426312772017075014672 00000000000000// Copyright (C) 2011-2015 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 UDP_SOCKET_H #define UDP_SOCKET_H 1 #ifndef BOOST_ASIO_HPP #error "asio.hpp must be included before including this, see asiolink.h as to why" #endif #include #include #include // for some IPC/network system calls #include #include #include #include #include namespace isc { namespace asiolink { /// \brief The \c UDPSocket class is a concrete derived class of \c IOAsioSocket /// that represents a UDP socket. /// /// \param C Callback type template class UDPSocket : public IOAsioSocket { private: /// \brief Class is non-copyable UDPSocket(const UDPSocket&); UDPSocket& operator=(const UDPSocket&); public: enum { MIN_SIZE = 4096 // Minimum send and receive size }; /// \brief Constructor from an ASIO UDP socket. /// /// \param socket The ASIO representation of the UDP socket. It is assumed /// that the caller will open and close the socket, so these /// operations are a no-op for that socket. UDPSocket(boost::asio::ip::udp::socket& socket); /// \brief Constructor /// /// Used when the UDPSocket is being asked to manage its own internal /// socket. In this case, the open() and close() methods are used. /// /// \param service I/O Service object used to manage the socket. UDPSocket(IOService& service); /// \brief Destructor virtual ~UDPSocket(); /// \brief Return file descriptor of underlying socket virtual int getNative() const { return (socket_.native()); } /// \brief Return protocol of socket virtual int getProtocol() const { return (IPPROTO_UDP); } /// \brief Is "open()" synchronous? /// /// Indicates that the opening of a UDP socket is synchronous. virtual bool isOpenSynchronous() const { return true; } /// \brief Open Socket /// /// Opens the UDP socket. This is a synchronous operation. /// /// \param endpoint Endpoint to which the socket will send data. This is /// used to determine the address family trhat should be used for the /// underlying socket. /// \param callback Unused as the operation is synchronous. virtual void open(const IOEndpoint* endpoint, C& callback); /// \brief Send Asynchronously /// /// Calls the underlying socket's async_send_to() method to send a packet of /// data asynchronously to the remote endpoint. The callback will be called /// on completion. /// /// \param data Data to send /// \param length Length of data to send /// \param endpoint Target of the send /// \param callback Callback object. virtual void asyncSend(const void* data, size_t length, const IOEndpoint* endpoint, C& callback); /// \brief Receive Asynchronously /// /// Calls the underlying socket's async_receive_from() method to read a /// packet of data from a remote endpoint. Arrival of the data is signalled /// via a call to the callback function. /// /// \param data Buffer to receive incoming message /// \param length Length of the data buffer /// \param offset Offset into buffer where data is to be put /// \param endpoint Source of the communication /// \param callback Callback object virtual void asyncReceive(void* data, size_t length, size_t offset, IOEndpoint* endpoint, C& callback); /// \brief Process received data /// /// See the description of IOAsioSocket::receiveComplete for a complete /// description of this method. /// /// \param staging Pointer to the start of the staging buffer. /// \param length Amount of data in the staging buffer. /// \param cumulative Amount of data received before the staging buffer is /// processed. /// \param offset Unused. /// \param expected unused. /// \param outbuff Output buffer. Data in the staging buffer is be copied /// to this output buffer in the call. /// /// \return Always true virtual bool processReceivedData(const void* staging, size_t length, size_t& cumulative, size_t& offset, size_t& expected, isc::util::OutputBufferPtr& outbuff); /// \brief Cancel I/O On Socket virtual void cancel(); /// \brief Close socket virtual void close(); private: // Two variables to hold the socket - a socket and a pointer to it. This // handles the case where a socket is passed to the UDPSocket on // construction, or where it is asked to manage its own socket. boost::asio::ip::udp::socket* socket_ptr_; ///< Pointer to own socket boost::asio::ip::udp::socket& socket_; ///< Socket bool isopen_; ///< true when socket is open }; // Constructor - caller manages socket template UDPSocket::UDPSocket(boost::asio::ip::udp::socket& socket) : socket_ptr_(NULL), socket_(socket), isopen_(true) { } // Constructor - create socket on the fly template UDPSocket::UDPSocket(IOService& service) : socket_ptr_(new boost::asio::ip::udp::socket(service.get_io_service())), socket_(*socket_ptr_), isopen_(false) { } // Destructor. Only delete the socket if we are managing it. template UDPSocket::~UDPSocket() { delete socket_ptr_; } // Open the socket. template void UDPSocket::open(const IOEndpoint* endpoint, C&) { // Ignore opens on already-open socket. (Don't throw a failure because // of uncertainties as to what precedes whan when using asynchronous I/O.) // It also allows us a treat a passed-in socket in exactly the same way as // a self-managed socket (in that we can call the open() and close() methods // of this class). if (!isopen_) { if (endpoint->getFamily() == AF_INET) { socket_.open(boost::asio::ip::udp::v4()); } else { socket_.open(boost::asio::ip::udp::v6()); } isopen_ = true; // Ensure it can send and receive at least 4K buffers. boost::asio::ip::udp::socket::send_buffer_size snd_size; socket_.get_option(snd_size); if (snd_size.value() < MIN_SIZE) { snd_size = MIN_SIZE; socket_.set_option(snd_size); } boost::asio::ip::udp::socket::receive_buffer_size rcv_size; socket_.get_option(rcv_size); if (rcv_size.value() < MIN_SIZE) { rcv_size = MIN_SIZE; socket_.set_option(rcv_size); } } } // Send a message. Should never do this if the socket is not open, so throw // an exception if this is the case. template void UDPSocket::asyncSend(const void* data, size_t length, const IOEndpoint* endpoint, C& callback) { if (isopen_) { // Upconvert to a UDPEndpoint. We need to do this because although // IOEndpoint is the base class of UDPEndpoint and TCPEndpoint, it // does not contain a method for getting at the underlying endpoint // type - that is in the derived class and the two classes differ on // return type. assert(endpoint->getProtocol() == IPPROTO_UDP); const UDPEndpoint* udp_endpoint = static_cast(endpoint); // ... and send the message. socket_.async_send_to(boost::asio::buffer(data, length), udp_endpoint->getASIOEndpoint(), callback); } else { isc_throw(SocketNotOpen, "attempt to send on a UDP socket that is not open"); } } // Receive a message. Should never do this if the socket is not open, so throw // an exception if this is the case. template void UDPSocket::asyncReceive(void* data, size_t length, size_t offset, IOEndpoint* endpoint, C& callback) { if (isopen_) { // Upconvert the endpoint again. assert(endpoint->getProtocol() == IPPROTO_UDP); UDPEndpoint* udp_endpoint = static_cast(endpoint); // Ensure we can write into the buffer if (offset >= length) { isc_throw(BufferOverflow, "attempt to read into area beyond end of " "UDP receive buffer"); } void* buffer_start = static_cast(static_cast(data) + offset); // Issue the read socket_.async_receive_from(boost::asio::buffer(buffer_start, length - offset), udp_endpoint->getASIOEndpoint(), callback); } else { isc_throw(SocketNotOpen, "attempt to receive from a UDP socket that is not open"); } } // Receive complete. Just copy the data across to the output buffer and // update arguments as appropriate. template bool UDPSocket::processReceivedData(const void* staging, size_t length, size_t& cumulative, size_t& offset, size_t& expected, isc::util::OutputBufferPtr& outbuff) { // Set return values to what we should expect. cumulative = length; expected = length; offset = 0; // Copy data across outbuff->writeData(staging, length); // ... and mark that we have everything. return (true); } // Cancel I/O on the socket. No-op if the socket is not open. template void UDPSocket::cancel() { if (isopen_) { socket_.cancel(); } } // Close the socket down. Can only do this if the socket is open and we are // managing it ourself. template void UDPSocket::close() { if (isopen_ && socket_ptr_) { socket_.close(); isopen_ = false; } } } // namespace asiolink } // namespace isc #endif // UDP_SOCKET_H kea-1.1.0/src/lib/asiolink/tests/0000775000175000017500000000000012772742661013602 500000000000000kea-1.1.0/src/lib/asiolink/tests/Makefile.in0000664000175000017500000015013212772742615015570 00000000000000# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ TESTS = $(am__EXEEXT_1) @HAVE_GTEST_TRUE@am__append_1 = run_unittests @HAVE_GTEST_TRUE@@USE_GXX_TRUE@am__append_2 = -Wno-unused-parameter noinst_PROGRAMS = $(am__EXEEXT_2) subdir = src/lib/asiolink/tests DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/depcomp ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4macros/ax_boost_for_kea.m4 \ $(top_srcdir)/m4macros/ax_isc_rpath.m4 \ $(top_srcdir)/m4macros/libtool.m4 \ $(top_srcdir)/m4macros/ltoptions.m4 \ $(top_srcdir)/m4macros/ltsugar.m4 \ $(top_srcdir)/m4macros/ltversion.m4 \ $(top_srcdir)/m4macros/lt~obsolete.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = @HAVE_GTEST_TRUE@am__EXEEXT_1 = run_unittests$(EXEEXT) am__EXEEXT_2 = $(am__EXEEXT_1) PROGRAMS = $(noinst_PROGRAMS) am__run_unittests_SOURCES_DIST = run_unittests.cc \ io_address_unittest.cc io_endpoint_unittest.cc \ io_socket_unittest.cc interval_timer_unittest.cc \ tcp_endpoint_unittest.cc tcp_socket_unittest.cc \ udp_endpoint_unittest.cc udp_socket_unittest.cc \ io_service_unittest.cc dummy_io_callback_unittest.cc @HAVE_GTEST_TRUE@am_run_unittests_OBJECTS = \ @HAVE_GTEST_TRUE@ run_unittests-run_unittests.$(OBJEXT) \ @HAVE_GTEST_TRUE@ run_unittests-io_address_unittest.$(OBJEXT) \ @HAVE_GTEST_TRUE@ run_unittests-io_endpoint_unittest.$(OBJEXT) \ @HAVE_GTEST_TRUE@ run_unittests-io_socket_unittest.$(OBJEXT) \ @HAVE_GTEST_TRUE@ run_unittests-interval_timer_unittest.$(OBJEXT) \ @HAVE_GTEST_TRUE@ run_unittests-tcp_endpoint_unittest.$(OBJEXT) \ @HAVE_GTEST_TRUE@ run_unittests-tcp_socket_unittest.$(OBJEXT) \ @HAVE_GTEST_TRUE@ run_unittests-udp_endpoint_unittest.$(OBJEXT) \ @HAVE_GTEST_TRUE@ run_unittests-udp_socket_unittest.$(OBJEXT) \ @HAVE_GTEST_TRUE@ run_unittests-io_service_unittest.$(OBJEXT) \ @HAVE_GTEST_TRUE@ run_unittests-dummy_io_callback_unittest.$(OBJEXT) run_unittests_OBJECTS = $(am_run_unittests_OBJECTS) am__DEPENDENCIES_1 = @HAVE_GTEST_TRUE@run_unittests_DEPENDENCIES = $(top_builddir)/src/lib/asiolink/libkea-asiolink.la \ @HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/log/libkea-log.la \ @HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/util/threads/libkea-threads.la \ @HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/util/unittests/libutil_unittests.la \ @HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/util/libkea-util.la \ @HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/exceptions/libkea-exceptions.la \ @HAVE_GTEST_TRUE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ @HAVE_GTEST_TRUE@ $(am__DEPENDENCIES_1) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = run_unittests_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(run_unittests_CXXFLAGS) $(CXXFLAGS) $(run_unittests_LDFLAGS) \ $(LDFLAGS) -o $@ AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CXXFLAGS) $(CXXFLAGS) AM_V_CXX = $(am__v_CXX_@AM_V@) am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@) am__v_CXX_0 = @echo " CXX " $@; am__v_CXX_1 = CXXLD = $(CXX) CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CXXLD = $(am__v_CXXLD_@AM_V@) am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@) am__v_CXXLD_0 = @echo " CXXLD " $@; am__v_CXXLD_1 = SOURCES = $(run_unittests_SOURCES) DIST_SOURCES = $(am__run_unittests_SOURCES_DIST) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags am__tty_colors_dummy = \ mgn= red= grn= lgn= blu= brg= std=; \ am__color_tests=no am__tty_colors = { \ $(am__tty_colors_dummy); \ if test "X$(AM_COLOR_TESTS)" = Xno; then \ am__color_tests=no; \ elif test "X$(AM_COLOR_TESTS)" = Xalways; then \ am__color_tests=yes; \ elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \ am__color_tests=yes; \ fi; \ if test $$am__color_tests = yes; then \ red=''; \ grn=''; \ lgn=''; \ blu=''; \ mgn=''; \ brg=''; \ std=''; \ fi; \ } DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ASCIIDOC = @ASCIIDOC@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BOOST_INCLUDES = @BOOST_INCLUDES@ BOOST_LIBS = @BOOST_LIBS@ BOTAN_TOOL = @BOTAN_TOOL@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CQL_CPPFLAGS = @CQL_CPPFLAGS@ CQL_LIBS = @CQL_LIBS@ CRYPTO_CFLAGS = @CRYPTO_CFLAGS@ CRYPTO_INCLUDES = @CRYPTO_INCLUDES@ CRYPTO_LDFLAGS = @CRYPTO_LDFLAGS@ CRYPTO_LIBS = @CRYPTO_LIBS@ CRYPTO_PACKAGE = @CRYPTO_PACKAGE@ CRYPTO_RPATH = @CRYPTO_RPATH@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DBLATEX = @DBLATEX@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DISTCHECK_BOOST_CONFIGURE_FLAG = @DISTCHECK_BOOST_CONFIGURE_FLAG@ DISTCHECK_CRYPTO_CONFIGURE_FLAG = @DISTCHECK_CRYPTO_CONFIGURE_FLAG@ DISTCHECK_GTEST_CONFIGURE_FLAG = @DISTCHECK_GTEST_CONFIGURE_FLAG@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ ELINKS = @ELINKS@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GENHTML = @GENHTML@ GREP = @GREP@ GTEST_CONFIG = @GTEST_CONFIG@ GTEST_INCLUDES = @GTEST_INCLUDES@ GTEST_LDADD = @GTEST_LDADD@ GTEST_LDFLAGS = @GTEST_LDFLAGS@ GTEST_SOURCE = @GTEST_SOURCE@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ KEA_CXXFLAGS = @KEA_CXXFLAGS@ LCOV = @LCOV@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LEXLIB = @LEXLIB@ LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LOG4CPLUS_INCLUDES = @LOG4CPLUS_INCLUDES@ LOG4CPLUS_LIBS = @LOG4CPLUS_LIBS@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ MYSQL_LIBS = @MYSQL_LIBS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PERL = @PERL@ PGSQL_CPPFLAGS = @PGSQL_CPPFLAGS@ PGSQL_LIBS = @PGSQL_LIBS@ PKG_CONFIG = @PKG_CONFIG@ PLANTUML = @PLANTUML@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SEP = @SEP@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ USE_LCOV = @USE_LCOV@ VALGRIND = @VALGRIND@ VERSION = @VERSION@ WARNING_GCC_44_STRICT_ALIASING_CFLAG = @WARNING_GCC_44_STRICT_ALIASING_CFLAG@ XSLTPROC = @XSLTPROC@ YACC = @YACC@ YFLAGS = @YFLAGS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib \ $(BOOST_INCLUDES) -DTEST_DATA_DIR=\"$(srcdir)/testdata\" AM_CXXFLAGS = $(KEA_CXXFLAGS) @USE_STATIC_LINK_TRUE@AM_LDFLAGS = -static CLEANFILES = *.gcno *.gcda TESTS_ENVIRONMENT = \ $(LIBTOOL) --mode=execute $(VALGRIND_COMMAND) @HAVE_GTEST_TRUE@run_unittests_SOURCES = run_unittests.cc \ @HAVE_GTEST_TRUE@ io_address_unittest.cc \ @HAVE_GTEST_TRUE@ io_endpoint_unittest.cc io_socket_unittest.cc \ @HAVE_GTEST_TRUE@ interval_timer_unittest.cc \ @HAVE_GTEST_TRUE@ tcp_endpoint_unittest.cc \ @HAVE_GTEST_TRUE@ tcp_socket_unittest.cc \ @HAVE_GTEST_TRUE@ udp_endpoint_unittest.cc \ @HAVE_GTEST_TRUE@ udp_socket_unittest.cc io_service_unittest.cc \ @HAVE_GTEST_TRUE@ dummy_io_callback_unittest.cc @HAVE_GTEST_TRUE@run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES) @HAVE_GTEST_TRUE@run_unittests_LDADD = $(top_builddir)/src/lib/asiolink/libkea-asiolink.la \ @HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/log/libkea-log.la \ @HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/util/threads/libkea-threads.la \ @HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/util/unittests/libutil_unittests.la \ @HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/util/libkea-util.la \ @HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/exceptions/libkea-exceptions.la \ @HAVE_GTEST_TRUE@ $(LOG4CPLUS_LIBS) $(BOOST_LIBS) \ @HAVE_GTEST_TRUE@ $(GTEST_LDADD) @HAVE_GTEST_TRUE@run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS) # Note: the ordering matters: -Wno-... must follow -Wextra (defined in # KEA_CXXFLAGS) @HAVE_GTEST_TRUE@run_unittests_CXXFLAGS = $(AM_CXXFLAGS) \ @HAVE_GTEST_TRUE@ $(am__append_2) all: all-am .SUFFIXES: .SUFFIXES: .cc .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/lib/asiolink/tests/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign src/lib/asiolink/tests/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-noinstPROGRAMS: @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list run_unittests$(EXEEXT): $(run_unittests_OBJECTS) $(run_unittests_DEPENDENCIES) $(EXTRA_run_unittests_DEPENDENCIES) @rm -f run_unittests$(EXEEXT) $(AM_V_CXXLD)$(run_unittests_LINK) $(run_unittests_OBJECTS) $(run_unittests_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-dummy_io_callback_unittest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-interval_timer_unittest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-io_address_unittest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-io_endpoint_unittest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-io_service_unittest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-io_socket_unittest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-run_unittests.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-tcp_endpoint_unittest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-tcp_socket_unittest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-udp_endpoint_unittest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-udp_socket_unittest.Po@am__quote@ .cc.o: @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $< .cc.obj: @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .cc.lo: @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $< run_unittests-run_unittests.o: run_unittests.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-run_unittests.o -MD -MP -MF $(DEPDIR)/run_unittests-run_unittests.Tpo -c -o run_unittests-run_unittests.o `test -f 'run_unittests.cc' || echo '$(srcdir)/'`run_unittests.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-run_unittests.Tpo $(DEPDIR)/run_unittests-run_unittests.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='run_unittests.cc' object='run_unittests-run_unittests.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-run_unittests.o `test -f 'run_unittests.cc' || echo '$(srcdir)/'`run_unittests.cc run_unittests-run_unittests.obj: run_unittests.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-run_unittests.obj -MD -MP -MF $(DEPDIR)/run_unittests-run_unittests.Tpo -c -o run_unittests-run_unittests.obj `if test -f 'run_unittests.cc'; then $(CYGPATH_W) 'run_unittests.cc'; else $(CYGPATH_W) '$(srcdir)/run_unittests.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-run_unittests.Tpo $(DEPDIR)/run_unittests-run_unittests.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='run_unittests.cc' object='run_unittests-run_unittests.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-run_unittests.obj `if test -f 'run_unittests.cc'; then $(CYGPATH_W) 'run_unittests.cc'; else $(CYGPATH_W) '$(srcdir)/run_unittests.cc'; fi` run_unittests-io_address_unittest.o: io_address_unittest.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-io_address_unittest.o -MD -MP -MF $(DEPDIR)/run_unittests-io_address_unittest.Tpo -c -o run_unittests-io_address_unittest.o `test -f 'io_address_unittest.cc' || echo '$(srcdir)/'`io_address_unittest.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-io_address_unittest.Tpo $(DEPDIR)/run_unittests-io_address_unittest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='io_address_unittest.cc' object='run_unittests-io_address_unittest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-io_address_unittest.o `test -f 'io_address_unittest.cc' || echo '$(srcdir)/'`io_address_unittest.cc run_unittests-io_address_unittest.obj: io_address_unittest.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-io_address_unittest.obj -MD -MP -MF $(DEPDIR)/run_unittests-io_address_unittest.Tpo -c -o run_unittests-io_address_unittest.obj `if test -f 'io_address_unittest.cc'; then $(CYGPATH_W) 'io_address_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/io_address_unittest.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-io_address_unittest.Tpo $(DEPDIR)/run_unittests-io_address_unittest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='io_address_unittest.cc' object='run_unittests-io_address_unittest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-io_address_unittest.obj `if test -f 'io_address_unittest.cc'; then $(CYGPATH_W) 'io_address_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/io_address_unittest.cc'; fi` run_unittests-io_endpoint_unittest.o: io_endpoint_unittest.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-io_endpoint_unittest.o -MD -MP -MF $(DEPDIR)/run_unittests-io_endpoint_unittest.Tpo -c -o run_unittests-io_endpoint_unittest.o `test -f 'io_endpoint_unittest.cc' || echo '$(srcdir)/'`io_endpoint_unittest.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-io_endpoint_unittest.Tpo $(DEPDIR)/run_unittests-io_endpoint_unittest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='io_endpoint_unittest.cc' object='run_unittests-io_endpoint_unittest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-io_endpoint_unittest.o `test -f 'io_endpoint_unittest.cc' || echo '$(srcdir)/'`io_endpoint_unittest.cc run_unittests-io_endpoint_unittest.obj: io_endpoint_unittest.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-io_endpoint_unittest.obj -MD -MP -MF $(DEPDIR)/run_unittests-io_endpoint_unittest.Tpo -c -o run_unittests-io_endpoint_unittest.obj `if test -f 'io_endpoint_unittest.cc'; then $(CYGPATH_W) 'io_endpoint_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/io_endpoint_unittest.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-io_endpoint_unittest.Tpo $(DEPDIR)/run_unittests-io_endpoint_unittest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='io_endpoint_unittest.cc' object='run_unittests-io_endpoint_unittest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-io_endpoint_unittest.obj `if test -f 'io_endpoint_unittest.cc'; then $(CYGPATH_W) 'io_endpoint_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/io_endpoint_unittest.cc'; fi` run_unittests-io_socket_unittest.o: io_socket_unittest.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-io_socket_unittest.o -MD -MP -MF $(DEPDIR)/run_unittests-io_socket_unittest.Tpo -c -o run_unittests-io_socket_unittest.o `test -f 'io_socket_unittest.cc' || echo '$(srcdir)/'`io_socket_unittest.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-io_socket_unittest.Tpo $(DEPDIR)/run_unittests-io_socket_unittest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='io_socket_unittest.cc' object='run_unittests-io_socket_unittest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-io_socket_unittest.o `test -f 'io_socket_unittest.cc' || echo '$(srcdir)/'`io_socket_unittest.cc run_unittests-io_socket_unittest.obj: io_socket_unittest.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-io_socket_unittest.obj -MD -MP -MF $(DEPDIR)/run_unittests-io_socket_unittest.Tpo -c -o run_unittests-io_socket_unittest.obj `if test -f 'io_socket_unittest.cc'; then $(CYGPATH_W) 'io_socket_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/io_socket_unittest.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-io_socket_unittest.Tpo $(DEPDIR)/run_unittests-io_socket_unittest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='io_socket_unittest.cc' object='run_unittests-io_socket_unittest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-io_socket_unittest.obj `if test -f 'io_socket_unittest.cc'; then $(CYGPATH_W) 'io_socket_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/io_socket_unittest.cc'; fi` run_unittests-interval_timer_unittest.o: interval_timer_unittest.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-interval_timer_unittest.o -MD -MP -MF $(DEPDIR)/run_unittests-interval_timer_unittest.Tpo -c -o run_unittests-interval_timer_unittest.o `test -f 'interval_timer_unittest.cc' || echo '$(srcdir)/'`interval_timer_unittest.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-interval_timer_unittest.Tpo $(DEPDIR)/run_unittests-interval_timer_unittest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='interval_timer_unittest.cc' object='run_unittests-interval_timer_unittest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-interval_timer_unittest.o `test -f 'interval_timer_unittest.cc' || echo '$(srcdir)/'`interval_timer_unittest.cc run_unittests-interval_timer_unittest.obj: interval_timer_unittest.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-interval_timer_unittest.obj -MD -MP -MF $(DEPDIR)/run_unittests-interval_timer_unittest.Tpo -c -o run_unittests-interval_timer_unittest.obj `if test -f 'interval_timer_unittest.cc'; then $(CYGPATH_W) 'interval_timer_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/interval_timer_unittest.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-interval_timer_unittest.Tpo $(DEPDIR)/run_unittests-interval_timer_unittest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='interval_timer_unittest.cc' object='run_unittests-interval_timer_unittest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-interval_timer_unittest.obj `if test -f 'interval_timer_unittest.cc'; then $(CYGPATH_W) 'interval_timer_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/interval_timer_unittest.cc'; fi` run_unittests-tcp_endpoint_unittest.o: tcp_endpoint_unittest.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-tcp_endpoint_unittest.o -MD -MP -MF $(DEPDIR)/run_unittests-tcp_endpoint_unittest.Tpo -c -o run_unittests-tcp_endpoint_unittest.o `test -f 'tcp_endpoint_unittest.cc' || echo '$(srcdir)/'`tcp_endpoint_unittest.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-tcp_endpoint_unittest.Tpo $(DEPDIR)/run_unittests-tcp_endpoint_unittest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='tcp_endpoint_unittest.cc' object='run_unittests-tcp_endpoint_unittest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-tcp_endpoint_unittest.o `test -f 'tcp_endpoint_unittest.cc' || echo '$(srcdir)/'`tcp_endpoint_unittest.cc run_unittests-tcp_endpoint_unittest.obj: tcp_endpoint_unittest.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-tcp_endpoint_unittest.obj -MD -MP -MF $(DEPDIR)/run_unittests-tcp_endpoint_unittest.Tpo -c -o run_unittests-tcp_endpoint_unittest.obj `if test -f 'tcp_endpoint_unittest.cc'; then $(CYGPATH_W) 'tcp_endpoint_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/tcp_endpoint_unittest.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-tcp_endpoint_unittest.Tpo $(DEPDIR)/run_unittests-tcp_endpoint_unittest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='tcp_endpoint_unittest.cc' object='run_unittests-tcp_endpoint_unittest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-tcp_endpoint_unittest.obj `if test -f 'tcp_endpoint_unittest.cc'; then $(CYGPATH_W) 'tcp_endpoint_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/tcp_endpoint_unittest.cc'; fi` run_unittests-tcp_socket_unittest.o: tcp_socket_unittest.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-tcp_socket_unittest.o -MD -MP -MF $(DEPDIR)/run_unittests-tcp_socket_unittest.Tpo -c -o run_unittests-tcp_socket_unittest.o `test -f 'tcp_socket_unittest.cc' || echo '$(srcdir)/'`tcp_socket_unittest.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-tcp_socket_unittest.Tpo $(DEPDIR)/run_unittests-tcp_socket_unittest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='tcp_socket_unittest.cc' object='run_unittests-tcp_socket_unittest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-tcp_socket_unittest.o `test -f 'tcp_socket_unittest.cc' || echo '$(srcdir)/'`tcp_socket_unittest.cc run_unittests-tcp_socket_unittest.obj: tcp_socket_unittest.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-tcp_socket_unittest.obj -MD -MP -MF $(DEPDIR)/run_unittests-tcp_socket_unittest.Tpo -c -o run_unittests-tcp_socket_unittest.obj `if test -f 'tcp_socket_unittest.cc'; then $(CYGPATH_W) 'tcp_socket_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/tcp_socket_unittest.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-tcp_socket_unittest.Tpo $(DEPDIR)/run_unittests-tcp_socket_unittest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='tcp_socket_unittest.cc' object='run_unittests-tcp_socket_unittest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-tcp_socket_unittest.obj `if test -f 'tcp_socket_unittest.cc'; then $(CYGPATH_W) 'tcp_socket_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/tcp_socket_unittest.cc'; fi` run_unittests-udp_endpoint_unittest.o: udp_endpoint_unittest.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-udp_endpoint_unittest.o -MD -MP -MF $(DEPDIR)/run_unittests-udp_endpoint_unittest.Tpo -c -o run_unittests-udp_endpoint_unittest.o `test -f 'udp_endpoint_unittest.cc' || echo '$(srcdir)/'`udp_endpoint_unittest.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-udp_endpoint_unittest.Tpo $(DEPDIR)/run_unittests-udp_endpoint_unittest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='udp_endpoint_unittest.cc' object='run_unittests-udp_endpoint_unittest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-udp_endpoint_unittest.o `test -f 'udp_endpoint_unittest.cc' || echo '$(srcdir)/'`udp_endpoint_unittest.cc run_unittests-udp_endpoint_unittest.obj: udp_endpoint_unittest.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-udp_endpoint_unittest.obj -MD -MP -MF $(DEPDIR)/run_unittests-udp_endpoint_unittest.Tpo -c -o run_unittests-udp_endpoint_unittest.obj `if test -f 'udp_endpoint_unittest.cc'; then $(CYGPATH_W) 'udp_endpoint_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/udp_endpoint_unittest.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-udp_endpoint_unittest.Tpo $(DEPDIR)/run_unittests-udp_endpoint_unittest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='udp_endpoint_unittest.cc' object='run_unittests-udp_endpoint_unittest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-udp_endpoint_unittest.obj `if test -f 'udp_endpoint_unittest.cc'; then $(CYGPATH_W) 'udp_endpoint_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/udp_endpoint_unittest.cc'; fi` run_unittests-udp_socket_unittest.o: udp_socket_unittest.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-udp_socket_unittest.o -MD -MP -MF $(DEPDIR)/run_unittests-udp_socket_unittest.Tpo -c -o run_unittests-udp_socket_unittest.o `test -f 'udp_socket_unittest.cc' || echo '$(srcdir)/'`udp_socket_unittest.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-udp_socket_unittest.Tpo $(DEPDIR)/run_unittests-udp_socket_unittest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='udp_socket_unittest.cc' object='run_unittests-udp_socket_unittest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-udp_socket_unittest.o `test -f 'udp_socket_unittest.cc' || echo '$(srcdir)/'`udp_socket_unittest.cc run_unittests-udp_socket_unittest.obj: udp_socket_unittest.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-udp_socket_unittest.obj -MD -MP -MF $(DEPDIR)/run_unittests-udp_socket_unittest.Tpo -c -o run_unittests-udp_socket_unittest.obj `if test -f 'udp_socket_unittest.cc'; then $(CYGPATH_W) 'udp_socket_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/udp_socket_unittest.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-udp_socket_unittest.Tpo $(DEPDIR)/run_unittests-udp_socket_unittest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='udp_socket_unittest.cc' object='run_unittests-udp_socket_unittest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-udp_socket_unittest.obj `if test -f 'udp_socket_unittest.cc'; then $(CYGPATH_W) 'udp_socket_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/udp_socket_unittest.cc'; fi` run_unittests-io_service_unittest.o: io_service_unittest.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-io_service_unittest.o -MD -MP -MF $(DEPDIR)/run_unittests-io_service_unittest.Tpo -c -o run_unittests-io_service_unittest.o `test -f 'io_service_unittest.cc' || echo '$(srcdir)/'`io_service_unittest.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-io_service_unittest.Tpo $(DEPDIR)/run_unittests-io_service_unittest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='io_service_unittest.cc' object='run_unittests-io_service_unittest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-io_service_unittest.o `test -f 'io_service_unittest.cc' || echo '$(srcdir)/'`io_service_unittest.cc run_unittests-io_service_unittest.obj: io_service_unittest.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-io_service_unittest.obj -MD -MP -MF $(DEPDIR)/run_unittests-io_service_unittest.Tpo -c -o run_unittests-io_service_unittest.obj `if test -f 'io_service_unittest.cc'; then $(CYGPATH_W) 'io_service_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/io_service_unittest.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-io_service_unittest.Tpo $(DEPDIR)/run_unittests-io_service_unittest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='io_service_unittest.cc' object='run_unittests-io_service_unittest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-io_service_unittest.obj `if test -f 'io_service_unittest.cc'; then $(CYGPATH_W) 'io_service_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/io_service_unittest.cc'; fi` run_unittests-dummy_io_callback_unittest.o: dummy_io_callback_unittest.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-dummy_io_callback_unittest.o -MD -MP -MF $(DEPDIR)/run_unittests-dummy_io_callback_unittest.Tpo -c -o run_unittests-dummy_io_callback_unittest.o `test -f 'dummy_io_callback_unittest.cc' || echo '$(srcdir)/'`dummy_io_callback_unittest.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-dummy_io_callback_unittest.Tpo $(DEPDIR)/run_unittests-dummy_io_callback_unittest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='dummy_io_callback_unittest.cc' object='run_unittests-dummy_io_callback_unittest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-dummy_io_callback_unittest.o `test -f 'dummy_io_callback_unittest.cc' || echo '$(srcdir)/'`dummy_io_callback_unittest.cc run_unittests-dummy_io_callback_unittest.obj: dummy_io_callback_unittest.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-dummy_io_callback_unittest.obj -MD -MP -MF $(DEPDIR)/run_unittests-dummy_io_callback_unittest.Tpo -c -o run_unittests-dummy_io_callback_unittest.obj `if test -f 'dummy_io_callback_unittest.cc'; then $(CYGPATH_W) 'dummy_io_callback_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/dummy_io_callback_unittest.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-dummy_io_callback_unittest.Tpo $(DEPDIR)/run_unittests-dummy_io_callback_unittest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='dummy_io_callback_unittest.cc' object='run_unittests-dummy_io_callback_unittest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-dummy_io_callback_unittest.obj `if test -f 'dummy_io_callback_unittest.cc'; then $(CYGPATH_W) 'dummy_io_callback_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/dummy_io_callback_unittest.cc'; fi` mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags check-TESTS: $(TESTS) @failed=0; all=0; xfail=0; xpass=0; skip=0; \ srcdir=$(srcdir); export srcdir; \ list=' $(TESTS) '; \ $(am__tty_colors); \ if test -n "$$list"; then \ for tst in $$list; do \ if test -f ./$$tst; then dir=./; \ elif test -f $$tst; then dir=; \ else dir="$(srcdir)/"; fi; \ if $(TESTS_ENVIRONMENT) $${dir}$$tst $(AM_TESTS_FD_REDIRECT); then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xpass=`expr $$xpass + 1`; \ failed=`expr $$failed + 1`; \ col=$$red; res=XPASS; \ ;; \ *) \ col=$$grn; res=PASS; \ ;; \ esac; \ elif test $$? -ne 77; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xfail=`expr $$xfail + 1`; \ col=$$lgn; res=XFAIL; \ ;; \ *) \ failed=`expr $$failed + 1`; \ col=$$red; res=FAIL; \ ;; \ esac; \ else \ skip=`expr $$skip + 1`; \ col=$$blu; res=SKIP; \ fi; \ echo "$${col}$$res$${std}: $$tst"; \ done; \ if test "$$all" -eq 1; then \ tests="test"; \ All=""; \ else \ tests="tests"; \ All="All "; \ fi; \ if test "$$failed" -eq 0; then \ if test "$$xfail" -eq 0; then \ banner="$$All$$all $$tests passed"; \ else \ if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ fi; \ else \ if test "$$xpass" -eq 0; then \ banner="$$failed of $$all $$tests failed"; \ else \ if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ fi; \ fi; \ dashes="$$banner"; \ skipped=""; \ if test "$$skip" -ne 0; then \ if test "$$skip" -eq 1; then \ skipped="($$skip test was not run)"; \ else \ skipped="($$skip tests were not run)"; \ fi; \ test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$skipped"; \ fi; \ report=""; \ if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ report="Please report to $(PACKAGE_BUGREPORT)"; \ test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$report"; \ fi; \ dashes=`echo "$$dashes" | sed s/./=/g`; \ if test "$$failed" -eq 0; then \ col="$$grn"; \ else \ col="$$red"; \ fi; \ echo "$${col}$$dashes$${std}"; \ echo "$${col}$$banner$${std}"; \ test -z "$$skipped" || echo "$${col}$$skipped$${std}"; \ test -z "$$report" || echo "$${col}$$report$${std}"; \ echo "$${col}$$dashes$${std}"; \ test "$$failed" -eq 0; \ else :; fi distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am $(MAKE) $(AM_MAKEFLAGS) check-TESTS check: check-am all-am: Makefile $(PROGRAMS) installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool clean-noinstPROGRAMS \ mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: check-am install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-TESTS check-am clean \ clean-generic clean-libtool clean-noinstPROGRAMS cscopelist-am \ ctags ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: kea-1.1.0/src/lib/asiolink/tests/udp_endpoint_unittest.cc0000664000175000017500000000266512772017075020463 00000000000000// Copyright (C) 2011-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 #include #include #include #include #include using namespace isc::asiolink; using namespace std; // This test checks that the endpoint can manage its own internal // boost::asio::ip::udp::endpoint object. TEST(UDPEndpointTest, v4Address) { const string test_address("192.0.2.1"); const unsigned short test_port = 5301; IOAddress address(test_address); UDPEndpoint endpoint(address, test_port); EXPECT_TRUE(address == endpoint.getAddress()); EXPECT_EQ(test_port, endpoint.getPort()); EXPECT_EQ(static_cast(IPPROTO_UDP), endpoint.getProtocol()); EXPECT_EQ(AF_INET, endpoint.getFamily()); } TEST(UDPEndpointTest, v6Address) { const string test_address("2001:db8::1235"); const unsigned short test_port = 5302; IOAddress address(test_address); UDPEndpoint endpoint(address, test_port); EXPECT_TRUE(address == endpoint.getAddress()); EXPECT_EQ(test_port, endpoint.getPort()); EXPECT_EQ(static_cast(IPPROTO_UDP), endpoint.getProtocol()); EXPECT_EQ(AF_INET6, endpoint.getFamily()); } kea-1.1.0/src/lib/asiolink/tests/dummy_io_callback_unittest.cc0000664000175000017500000000141712772017075021423 00000000000000// Copyright (C) 2014-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 #include #include #include using namespace isc::asiolink; using namespace boost::asio; namespace { // begin unnamed namespace TEST(DummyIOCallbackTest, throws) { DummyIOCallback cb; boost::system::error_code error_code; // All methods should throw isc::Unexpected. EXPECT_THROW(cb(error_code), isc::Unexpected); EXPECT_THROW(cb(error_code, 42), isc::Unexpected); } } // end of unnamed namespace kea-1.1.0/src/lib/asiolink/tests/io_socket_unittest.cc0000664000175000017500000000146612772017075017750 00000000000000// Copyright (C) 2011-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 #include #include #include #include using namespace isc::asiolink; TEST(IOSocketTest, dummySockets) { EXPECT_EQ(static_cast(IPPROTO_UDP), IOSocket::getDummyUDPSocket().getProtocol()); EXPECT_EQ(static_cast(IPPROTO_TCP), IOSocket::getDummyTCPSocket().getProtocol()); EXPECT_EQ(-1, IOSocket::getDummyUDPSocket().getNative()); EXPECT_EQ(-1, IOSocket::getDummyTCPSocket().getNative()); } kea-1.1.0/src/lib/asiolink/tests/tcp_endpoint_unittest.cc0000664000175000017500000000266512772017075020461 00000000000000// Copyright (C) 2011-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 #include #include #include #include #include using namespace isc::asiolink; using namespace std; // This test checks that the endpoint can manage its own internal // boost::asio::ip::tcp::endpoint object. TEST(TCPEndpointTest, v4Address) { const string test_address("192.0.2.1"); const unsigned short test_port = 5301; IOAddress address(test_address); TCPEndpoint endpoint(address, test_port); EXPECT_TRUE(address == endpoint.getAddress()); EXPECT_EQ(test_port, endpoint.getPort()); EXPECT_EQ(static_cast(IPPROTO_TCP), endpoint.getProtocol()); EXPECT_EQ(AF_INET, endpoint.getFamily()); } TEST(TCPEndpointTest, v6Address) { const string test_address("2001:db8::1235"); const unsigned short test_port = 5302; IOAddress address(test_address); TCPEndpoint endpoint(address, test_port); EXPECT_TRUE(address == endpoint.getAddress()); EXPECT_EQ(test_port, endpoint.getPort()); EXPECT_EQ(static_cast(IPPROTO_TCP), endpoint.getProtocol()); EXPECT_EQ(AF_INET6, endpoint.getFamily()); } kea-1.1.0/src/lib/asiolink/tests/Makefile.am0000664000175000017500000000335112772017075015552 00000000000000AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib AM_CPPFLAGS += $(BOOST_INCLUDES) AM_CPPFLAGS += -DTEST_DATA_DIR=\"$(srcdir)/testdata\" AM_CXXFLAGS = $(KEA_CXXFLAGS) if USE_STATIC_LINK AM_LDFLAGS = -static endif CLEANFILES = *.gcno *.gcda TESTS_ENVIRONMENT = \ $(LIBTOOL) --mode=execute $(VALGRIND_COMMAND) TESTS = if HAVE_GTEST TESTS += run_unittests run_unittests_SOURCES = run_unittests.cc run_unittests_SOURCES += io_address_unittest.cc run_unittests_SOURCES += io_endpoint_unittest.cc run_unittests_SOURCES += io_socket_unittest.cc run_unittests_SOURCES += interval_timer_unittest.cc run_unittests_SOURCES += tcp_endpoint_unittest.cc run_unittests_SOURCES += tcp_socket_unittest.cc run_unittests_SOURCES += udp_endpoint_unittest.cc run_unittests_SOURCES += udp_socket_unittest.cc run_unittests_SOURCES += io_service_unittest.cc run_unittests_SOURCES += dummy_io_callback_unittest.cc run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES) run_unittests_LDADD = $(top_builddir)/src/lib/asiolink/libkea-asiolink.la run_unittests_LDADD += $(top_builddir)/src/lib/log/libkea-log.la run_unittests_LDADD += $(top_builddir)/src/lib/util/threads/libkea-threads.la run_unittests_LDADD += $(top_builddir)/src/lib/util/unittests/libutil_unittests.la run_unittests_LDADD += $(top_builddir)/src/lib/util/libkea-util.la run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libkea-exceptions.la run_unittests_LDADD += $(LOG4CPLUS_LIBS) $(BOOST_LIBS) $(GTEST_LDADD) run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS) # Note: the ordering matters: -Wno-... must follow -Wextra (defined in # KEA_CXXFLAGS) run_unittests_CXXFLAGS = $(AM_CXXFLAGS) if USE_GXX run_unittests_CXXFLAGS += -Wno-unused-parameter endif endif noinst_PROGRAMS = $(TESTS) kea-1.1.0/src/lib/asiolink/tests/udp_socket_unittest.cc0000664000175000017500000002774612772445242020143 00000000000000// Copyright (C) 2011-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/. /// \brief Test of UDPSocket /// /// Tests the functionality of a UDPSocket by working through an open-send- /// receive-close sequence and checking that the asynchronous notifications /// work. #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace boost::asio; using namespace isc::util; using namespace isc::asiolink; using namespace std; namespace { const char SERVER_ADDRESS[] = "127.0.0.1"; const unsigned short SERVER_PORT = 5301; // TODO: Shouldn't we send something that is real message? const char OUTBOUND_DATA[] = "Data sent from client to server"; const char INBOUND_DATA[] = "Returned data from server to client"; } /// /// An instance of this object is passed to the asynchronous I/O functions /// and the operator() method is called when when an asynchronous I/O /// completes. The arguments to the completion callback are stored for later /// retrieval. class UDPCallback { public: struct PrivateData { PrivateData() : error_code_(), length_(0), called_(false), name_("") {} boost::system::error_code error_code_; ///< Completion error code size_t length_; ///< Number of bytes transferred bool called_; ///< Set true when callback called std::string name_; ///< Which of the objects this is }; /// \brief Constructor /// /// Constructs the object. It also creates the data member pointed to by /// a shared pointer. When used as a callback object, this is copied as it /// is passed into the asynchronous function. This means that there are two /// objects and inspecting the one we passed in does not tell us anything. /// /// Therefore we use a boost::shared_ptr. When the object is copied, the /// shared pointer is copied, which leaves both objects pointing to the same /// data. /// /// \param which Which of the two callback objects this is UDPCallback(const std::string& which) : ptr_(new PrivateData()) { setName(which); } /// \brief Destructor /// /// No code needed, destroying the shared pointer destroys the private data. virtual ~UDPCallback() {} /// \brief Callback Function /// /// Called when an asynchronous I/O completes, this stores the /// completion error code and the number of bytes transferred. /// /// \param ec I/O completion error code passed to callback function. /// \param length Number of bytes transferred virtual void operator()(boost::system::error_code ec, size_t length = 0) { ptr_->error_code_ = ec; setLength(length); setCalled(true); } /// \brief Get I/O completion error code int getCode() { return (ptr_->error_code_.value()); } /// \brief Set I/O completion code /// /// \param code New value of completion code void setCode(int code) { ptr_->error_code_ = boost::system::error_code(code, boost::system::error_code().category()); } /// \brief Get number of bytes transferred in I/O size_t getLength() const { return (ptr_->length_); } /// \brief Set number of bytes transferred in I/O /// /// \param length New value of length parameter void setLength(size_t length) { ptr_->length_ = length; } /// \brief Get flag to say when callback was called bool getCalled() const { return (ptr_->called_); } /// \brief Set flag to say when callback was called /// /// \param called New value of called parameter void setCalled(bool called) { ptr_->called_ = called; } /// \brief Return instance of callback name std::string getName() const { return (ptr_->name_); } /// \brief Set callback name /// /// \param name New value of the callback name void setName(const std::string& name) { ptr_->name_ = name; } private: boost::shared_ptr ptr_; ///< Pointer to private data }; // Receive complete method should return true regardless of what is in the first // two bytes of a buffer. TEST(UDPSocket, processReceivedData) { IOService service; // Used to instantiate socket UDPSocket test(service); // Socket under test uint8_t inbuff[32]; // Buffer to check OutputBufferPtr outbuff(new OutputBuffer(16)); // Where data is put // cppcheck-suppress variableScope size_t expected; // Expected amount of data // cppcheck-suppress variableScope size_t offset; // Where to put next data // cppcheck-suppress variableScope size_t cumulative; // Cumulative data received // Set some dummy values in the buffer to check for (uint8_t i = 0; i < sizeof(inbuff); ++i) { inbuff[i] = i; } // Expect that the value is true whatever number is written in the first // two bytes of the buffer. uint16_t count = 0; for (uint32_t i = 0; i < (2 << 16); ++i, ++count) { writeUint16(count, inbuff, sizeof(inbuff)); // Set some random values cumulative = 5; offset = 10; expected = 15; outbuff->clear(); bool completed = test.processReceivedData(inbuff, sizeof(inbuff), cumulative, offset, expected, outbuff); EXPECT_TRUE(completed); EXPECT_EQ(sizeof(inbuff), cumulative); EXPECT_EQ(0, offset); EXPECT_EQ(sizeof(inbuff), expected); const uint8_t* dataptr = static_cast(outbuff->getData()); EXPECT_TRUE(equal(inbuff, inbuff + sizeof(inbuff) - 1, dataptr)); } } // TODO: Need to add a test to check the cancel() method // Tests the operation of a UDPSocket by opening it, sending an asynchronous // message to a server, receiving an asynchronous message from the server and // closing. TEST(UDPSocket, SequenceTest) { // Common objects. IOService service; // Service object for async control // Server IOAddress server_address(SERVER_ADDRESS); // Address of target server UDPCallback server_cb("Server"); // Server callback UDPEndpoint server_endpoint( // Endpoint describing server server_address, SERVER_PORT); UDPEndpoint server_remote_endpoint; // Address where server received message from // The client - the UDPSocket being tested UDPSocket client(service);// Socket under test UDPCallback client_cb("Client"); // Async I/O callback function UDPEndpoint client_remote_endpoint; // Where client receives message from size_t client_cumulative = 0; // Cumulative data received size_t client_offset = 0; // Offset into buffer where data is put size_t client_expected = 0; // Expected amount of data OutputBufferPtr client_buffer(new OutputBuffer(16)); // Where data is put // The server - with which the client communicates. For convenience, we // use the same io_service, and use the endpoint object created for // the client to send to as the endpoint object in the constructor. boost::asio::ip::udp::socket server(service.get_io_service(), server_endpoint.getASIOEndpoint()); server.set_option(socket_base::reuse_address(true)); // Assertion to ensure that the server buffer is large enough char data[UDPSocket::MIN_SIZE]; ASSERT_GT(sizeof(data), sizeof(OUTBOUND_DATA)); // Open the client socket - the operation should be synchronous EXPECT_TRUE(client.isOpenSynchronous()); client.open(&server_endpoint, client_cb); // Issue read on the server. Completion callback should not have run. server_cb.setCalled(false); server_cb.setCode(42); // Answer to Life, the Universe and Everything! server.async_receive_from(buffer(data, sizeof(data)), server_remote_endpoint.getASIOEndpoint(), server_cb); EXPECT_FALSE(server_cb.getCalled()); // Write something to the server using the client - the callback should not // be called until we call the io_service.run() method. client_cb.setCalled(false); client_cb.setCode(7); // Arbitrary number client.asyncSend(OUTBOUND_DATA, sizeof(OUTBOUND_DATA), &server_endpoint, client_cb); EXPECT_FALSE(client_cb.getCalled()); // Execute the two callbacks. service.run_one(); service.run_one(); EXPECT_TRUE(client_cb.getCalled()); EXPECT_EQ(0, client_cb.getCode()); EXPECT_EQ(sizeof(OUTBOUND_DATA), client_cb.getLength()); EXPECT_TRUE(server_cb.getCalled()); EXPECT_EQ(0, server_cb.getCode()); EXPECT_EQ(sizeof(OUTBOUND_DATA), server_cb.getLength()); EXPECT_TRUE(equal(&data[0], &data[server_cb.getLength() - 1], OUTBOUND_DATA)); // Now return data from the server to the client. Issue the read on the // client. client_cb.setLength(12345); // Arbitrary number client_cb.setCalled(false); client_cb.setCode(32); // Arbitrary number client.asyncReceive(data, sizeof(data), client_cumulative, &client_remote_endpoint, client_cb); // Issue the write on the server side to the source of the data it received. server_cb.setLength(22345); // Arbitrary number server_cb.setCalled(false); server_cb.setCode(232); // Arbitrary number server.async_send_to(buffer(INBOUND_DATA, sizeof(INBOUND_DATA)), server_remote_endpoint.getASIOEndpoint(), server_cb); // Expect two callbacks to run. service.run_one(); service.run_one(); EXPECT_TRUE(client_cb.getCalled()); EXPECT_EQ(0, client_cb.getCode()); EXPECT_EQ(sizeof(INBOUND_DATA), client_cb.getLength()); EXPECT_TRUE(server_cb.getCalled()); EXPECT_EQ(0, server_cb.getCode()); EXPECT_EQ(sizeof(INBOUND_DATA), server_cb.getLength()); EXPECT_TRUE(equal(&data[0], &data[server_cb.getLength() - 1], INBOUND_DATA)); // Check that the address/port received by the client corresponds to the // address and port the server is listening on. EXPECT_TRUE(server_address == client_remote_endpoint.getAddress()); EXPECT_EQ(SERVER_PORT, client_remote_endpoint.getPort()); // Check that the receive received a complete buffer's worth of data. EXPECT_TRUE(client.processReceivedData(&data[0], client_cb.getLength(), client_cumulative, client_offset, client_expected, client_buffer)); EXPECT_EQ(client_cb.getLength(), client_cumulative); EXPECT_EQ(0, client_offset); EXPECT_EQ(client_cb.getLength(), client_expected); EXPECT_EQ(client_cb.getLength(), client_buffer->getLength()); // ...and check that the data was copied to the output client buffer. const char* client_char_data = static_cast(client_buffer->getData()); EXPECT_TRUE(equal(&data[0], &data[client_cb.getLength() - 1], client_char_data)); // Close client and server. EXPECT_NO_THROW(client.close()); EXPECT_NO_THROW(server.close()); } kea-1.1.0/src/lib/asiolink/tests/io_service_unittest.cc0000664000175000017500000000241112772017075020107 00000000000000// Copyright (C) 2013-2015 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 #include #include #include using namespace isc::asiolink; namespace { void postedEvent(std::vector* destination, int value) { destination->push_back(value); } // Check the posted events are called, in the same order they are posted. TEST(IOService, post) { std::vector called; IOService service; // Post two events service.post(boost::bind(&postedEvent, &called, 1)); service.post(boost::bind(&postedEvent, &called, 2)); service.post(boost::bind(&postedEvent, &called, 3)); // They have not yet been called EXPECT_TRUE(called.empty()); // Process two events service.run_one(); service.run_one(); // Both events were called in the right order ASSERT_EQ(2, called.size()); EXPECT_EQ(1, called[0]); EXPECT_EQ(2, called[1]); // Test that poll() executes the last handler. service.poll(); ASSERT_EQ(3, called.size()); EXPECT_EQ(3, called[2]); } } kea-1.1.0/src/lib/asiolink/tests/run_unittests.cc0000664000175000017500000000114012772017075016745 00000000000000// Copyright (C) 2009-2015 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 #include #include int main(int argc, char* argv[]) { ::testing::InitGoogleTest(&argc, argv); // Initialize Google test isc::log::LoggerManager::init("unittest"); // Set a root logger name return (isc::util::unittests::run_all()); } kea-1.1.0/src/lib/asiolink/tests/io_endpoint_unittest.cc0000664000175000017500000003003012772017075020265 00000000000000// Copyright (C) 2011-2015 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 #include #include #include #include #include #include #include #include #include #include using namespace isc::asiolink; namespace { typedef boost::shared_ptr ConstIOEndpointPtr; TEST(IOEndpointTest, createUDPv4) { ConstIOEndpointPtr ep(IOEndpoint::create(IPPROTO_UDP, IOAddress("192.0.2.1"), 53210)); EXPECT_EQ("192.0.2.1", ep->getAddress().toText()); EXPECT_EQ(53210, ep->getPort()); EXPECT_EQ(AF_INET, ep->getFamily()); EXPECT_EQ(AF_INET, ep->getAddress().getFamily()); EXPECT_EQ(static_cast(IPPROTO_UDP), ep->getProtocol()); } TEST(IOEndpointTest, createTCPv4) { ConstIOEndpointPtr ep(IOEndpoint::create(IPPROTO_TCP, IOAddress("192.0.2.1"), 5301)); EXPECT_EQ("192.0.2.1", ep->getAddress().toText()); EXPECT_EQ(5301, ep->getPort()); EXPECT_EQ(AF_INET, ep->getFamily()); EXPECT_EQ(AF_INET, ep->getAddress().getFamily()); EXPECT_EQ(static_cast(IPPROTO_TCP), ep->getProtocol()); } TEST(IOEndpointTest, createUDPv6) { ConstIOEndpointPtr ep(IOEndpoint::create(IPPROTO_UDP, IOAddress("2001:db8::1234"), 5302)); EXPECT_EQ("2001:db8::1234", ep->getAddress().toText()); EXPECT_EQ(5302, ep->getPort()); EXPECT_EQ(AF_INET6, ep->getFamily()); EXPECT_EQ(AF_INET6, ep->getAddress().getFamily()); EXPECT_EQ(static_cast(IPPROTO_UDP), ep->getProtocol()); } TEST(IOEndpointTest, createTCPv6) { ConstIOEndpointPtr ep(IOEndpoint::create(IPPROTO_TCP, IOAddress("2001:db8::1234"), 5303)); EXPECT_EQ("2001:db8::1234", ep->getAddress().toText()); EXPECT_EQ(5303, ep->getPort()); EXPECT_EQ(AF_INET6, ep->getFamily()); EXPECT_EQ(AF_INET6, ep->getAddress().getFamily()); EXPECT_EQ(static_cast(IPPROTO_TCP), ep->getProtocol()); } TEST(IOEndpointTest, equality) { std::vector epv; epv.push_back(ConstIOEndpointPtr( IOEndpoint::create(IPPROTO_TCP, IOAddress("2001:db8::1234"), 5303))); epv.push_back(ConstIOEndpointPtr( IOEndpoint::create(IPPROTO_UDP, IOAddress("2001:db8::1234"), 5303))); epv.push_back(ConstIOEndpointPtr( IOEndpoint::create(IPPROTO_TCP, IOAddress("2001:db8::1234"), 5304))); epv.push_back(ConstIOEndpointPtr( IOEndpoint::create(IPPROTO_UDP, IOAddress("2001:db8::1234"), 5304))); epv.push_back(ConstIOEndpointPtr( IOEndpoint::create(IPPROTO_TCP, IOAddress("2001:db8::1235"), 5303))); epv.push_back(ConstIOEndpointPtr( IOEndpoint::create(IPPROTO_UDP, IOAddress("2001:db8::1235"), 5303))); epv.push_back(ConstIOEndpointPtr( IOEndpoint::create(IPPROTO_TCP, IOAddress("2001:db8::1235"), 5304))); epv.push_back(ConstIOEndpointPtr( IOEndpoint::create(IPPROTO_UDP, IOAddress("2001:db8::1235"), 5304))); epv.push_back(ConstIOEndpointPtr( IOEndpoint::create(IPPROTO_TCP, IOAddress("192.0.2.1"), 5303))); epv.push_back(ConstIOEndpointPtr( IOEndpoint::create(IPPROTO_UDP, IOAddress("192.0.2.1"), 5303))); epv.push_back(ConstIOEndpointPtr( IOEndpoint::create(IPPROTO_TCP, IOAddress("192.0.2.1"), 5304))); epv.push_back(ConstIOEndpointPtr( IOEndpoint::create(IPPROTO_UDP, IOAddress("192.0.2.1"), 5304))); epv.push_back(ConstIOEndpointPtr( IOEndpoint::create(IPPROTO_TCP, IOAddress("192.0.2.2"), 5303))); epv.push_back(ConstIOEndpointPtr( IOEndpoint::create(IPPROTO_UDP, IOAddress("192.0.2.2"), 5303))); epv.push_back(ConstIOEndpointPtr( IOEndpoint::create(IPPROTO_TCP, IOAddress("192.0.2.2"), 5304))); epv.push_back(ConstIOEndpointPtr( IOEndpoint::create(IPPROTO_UDP, IOAddress("192.0.2.2"), 5304))); for (size_t i = 0; i < epv.size(); ++i) { for (size_t j = 0; j < epv.size(); ++j) { if (i != j) { // We use EXPECT_TRUE/FALSE instead of _EQ here, since // _EQ requires there is an operator<< as well EXPECT_FALSE(*epv[i] == *epv[j]); EXPECT_TRUE(*epv[i] != *epv[j]); } } } // Create a second array with exactly the same values. We use create() // again to make sure we get different endpoints std::vector epv2; epv2.push_back(ConstIOEndpointPtr( IOEndpoint::create(IPPROTO_TCP, IOAddress("2001:db8::1234"), 5303))); epv2.push_back(ConstIOEndpointPtr( IOEndpoint::create(IPPROTO_UDP, IOAddress("2001:db8::1234"), 5303))); epv2.push_back(ConstIOEndpointPtr( IOEndpoint::create(IPPROTO_TCP, IOAddress("2001:db8::1234"), 5304))); epv2.push_back(ConstIOEndpointPtr( IOEndpoint::create(IPPROTO_UDP, IOAddress("2001:db8::1234"), 5304))); epv2.push_back(ConstIOEndpointPtr( IOEndpoint::create(IPPROTO_TCP, IOAddress("2001:db8::1235"), 5303))); epv2.push_back(ConstIOEndpointPtr( IOEndpoint::create(IPPROTO_UDP, IOAddress("2001:db8::1235"), 5303))); epv2.push_back(ConstIOEndpointPtr( IOEndpoint::create(IPPROTO_TCP, IOAddress("2001:db8::1235"), 5304))); epv2.push_back(ConstIOEndpointPtr( IOEndpoint::create(IPPROTO_UDP, IOAddress("2001:db8::1235"), 5304))); epv2.push_back(ConstIOEndpointPtr( IOEndpoint::create(IPPROTO_TCP, IOAddress("192.0.2.1"), 5303))); epv2.push_back(ConstIOEndpointPtr( IOEndpoint::create(IPPROTO_UDP, IOAddress("192.0.2.1"), 5303))); epv2.push_back(ConstIOEndpointPtr( IOEndpoint::create(IPPROTO_TCP, IOAddress("192.0.2.1"), 5304))); epv2.push_back(ConstIOEndpointPtr( IOEndpoint::create(IPPROTO_UDP, IOAddress("192.0.2.1"), 5304))); epv2.push_back(ConstIOEndpointPtr( IOEndpoint::create(IPPROTO_TCP, IOAddress("192.0.2.2"), 5303))); epv2.push_back(ConstIOEndpointPtr( IOEndpoint::create(IPPROTO_UDP, IOAddress("192.0.2.2"), 5303))); epv2.push_back(ConstIOEndpointPtr( IOEndpoint::create(IPPROTO_TCP, IOAddress("192.0.2.2"), 5304))); epv2.push_back(ConstIOEndpointPtr( IOEndpoint::create(IPPROTO_UDP, IOAddress("192.0.2.2"), 5304))); for (size_t i = 0; i < epv.size(); ++i) { EXPECT_TRUE(*epv[i] == *epv2[i]); EXPECT_FALSE(*epv[i] != *epv2[i]); } } TEST(IOEndpointTest, createIPProto) { EXPECT_THROW(IOEndpoint::create(IPPROTO_IP, IOAddress("192.0.2.1"), 53210)->getAddress().toText(), IOError); } void sockAddrMatch(const struct sockaddr& actual_sa, const char* const expected_addr_text, const char* const expected_port_text) { struct addrinfo hints; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_DGRAM; // this shouldn't matter hints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV; struct addrinfo* res; ASSERT_EQ(0, getaddrinfo(expected_addr_text, expected_port_text, &hints, &res)); EXPECT_EQ(res->ai_family, actual_sa.sa_family); #ifdef HAVE_SA_LEN // ASIO doesn't seem to set sa_len, so we set it to the expected value res->ai_addr->sa_len = actual_sa.sa_len; #endif EXPECT_EQ(0, memcmp(res->ai_addr, &actual_sa, res->ai_addrlen)); freeaddrinfo(res); } TEST(IOEndpointTest, getSockAddr) { // UDP/IPv4 ConstIOEndpointPtr ep(IOEndpoint::create(IPPROTO_UDP, IOAddress("192.0.2.1"), 53210)); sockAddrMatch(ep->getSockAddr(), "192.0.2.1", "53210"); // UDP/IPv6 ep.reset(IOEndpoint::create(IPPROTO_UDP, IOAddress("2001:db8::53"), 53)); sockAddrMatch(ep->getSockAddr(), "2001:db8::53", "53"); // TCP/IPv4 ep.reset(IOEndpoint::create(IPPROTO_TCP, IOAddress("192.0.2.2"), 53211)); sockAddrMatch(ep->getSockAddr(), "192.0.2.2", "53211"); // TCP/IPv6 ep.reset(IOEndpoint::create(IPPROTO_UDP, IOAddress("2001:db8::5300"), 35)); sockAddrMatch(ep->getSockAddr(), "2001:db8::5300", "35"); } // A faked IOEndpoint for an uncommon address family. It wouldn't be possible // to create via the normal factory, so we define a special derived class // for it. class TestIOEndpoint : public IOEndpoint { virtual IOAddress getAddress() const { return IOAddress("2001:db8::bad:add"); } virtual uint16_t getPort() const { return (42); } virtual short getProtocol() const { return (IPPROTO_UDP); } virtual short getFamily() const { return (AF_UNSPEC); } virtual const struct sockaddr& getSockAddr() const { static struct sockaddr sa_placeholder; return (sa_placeholder); } }; void checkEndpointText(const std::string& expected, const IOEndpoint& ep) { std::ostringstream oss; oss << ep; EXPECT_EQ(expected, oss.str()); } // test operator<<. We simply confirm it appends the result of toText(). TEST(IOEndpointTest, LeftShiftOperator) { // UDP/IPv4 ConstIOEndpointPtr ep(IOEndpoint::create(IPPROTO_UDP, IOAddress("192.0.2.1"), 53210)); checkEndpointText("192.0.2.1:53210", *ep); // UDP/IPv6 ep.reset(IOEndpoint::create(IPPROTO_UDP, IOAddress("2001:db8::53"), 53)); checkEndpointText("[2001:db8::53]:53", *ep); // Same for TCP: shouldn't be different ep.reset(IOEndpoint::create(IPPROTO_TCP, IOAddress("192.0.2.1"), 53210)); checkEndpointText("192.0.2.1:53210", *ep); ep.reset(IOEndpoint::create(IPPROTO_TCP, IOAddress("2001:db8::53"), 53)); checkEndpointText("[2001:db8::53]:53", *ep); // Uncommon address family. The actual behavior doesn't matter much // in practice, but we check such input doesn't make it crash. // We explicitly instantiate the test EP because otherwise some compilers // would be confused and complain. TestIOEndpoint test_ep; checkEndpointText("2001:db8::bad:add:42", test_ep); } } kea-1.1.0/src/lib/asiolink/tests/io_address_unittest.cc0000664000175000017500000002620212772445242020101 00000000000000// Copyright (C) 2011-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 #include #include #include #include #include #include #include #include using namespace isc::asiolink; TEST(IOAddressTest, fromText) { IOAddress io_address_v4("192.0.2.1"); EXPECT_EQ("192.0.2.1", io_address_v4.toText()); IOAddress io_address_v6("2001:db8::1234"); EXPECT_EQ("2001:db8::1234", io_address_v6.toText()); // bogus IPv4 address-like input EXPECT_THROW(IOAddress("192.0.2.2.1"), IOError); // bogus IPv4 address-like input: out-of-range octet EXPECT_THROW(IOAddress("192.0.2.300"), IOError); // bogus IPv6 address-like input EXPECT_THROW(IOAddress("2001:db8:::1234"), IOError); // bogus IPv6 address-like input EXPECT_THROW(IOAddress("2001:db8::efgh"), IOError); } TEST(IOAddressTest, Equality) { EXPECT_TRUE(IOAddress("192.0.2.1") == IOAddress("192.0.2.1")); EXPECT_FALSE(IOAddress("192.0.2.1") != IOAddress("192.0.2.1")); EXPECT_TRUE(IOAddress("192.0.2.1") != IOAddress("192.0.2.2")); EXPECT_FALSE(IOAddress("192.0.2.1") == IOAddress("192.0.2.2")); EXPECT_TRUE(IOAddress("2001:db8::12") == IOAddress("2001:0DB8:0:0::0012")); EXPECT_FALSE(IOAddress("2001:db8::12") != IOAddress("2001:0DB8:0:0::0012")); EXPECT_TRUE(IOAddress("2001:db8::1234") != IOAddress("2001:db8::1235")); EXPECT_FALSE(IOAddress("2001:db8::1234") == IOAddress("2001:db8::1235")); EXPECT_TRUE(IOAddress("2001:db8::1234") != IOAddress("192.0.2.3")); EXPECT_FALSE(IOAddress("2001:db8::1234") == IOAddress("192.0.2.3")); } TEST(IOAddressTest, Family) { EXPECT_EQ(AF_INET, IOAddress("192.0.2.1").getFamily()); EXPECT_EQ(AF_INET6, IOAddress("2001:0DB8:0:0::0012").getFamily()); } TEST(IOAddressTest, fromBytes) { // 2001:db8:1::dead:beef uint8_t v6[] = { 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x01, 0, 0, 0, 0, 0, 0, 0xde, 0xad, 0xbe, 0xef }; uint8_t v4[] = { 192, 0 , 2, 3 }; IOAddress addr("::"); EXPECT_NO_THROW({ addr = IOAddress::fromBytes(AF_INET6, v6); }); EXPECT_EQ("2001:db8:1::dead:beef", addr.toText()); EXPECT_NO_THROW({ addr = IOAddress::fromBytes(AF_INET, v4); }); EXPECT_EQ(addr, IOAddress("192.0.2.3")); } TEST(IOAddressTest, toBytesV4) { // Address and network byte-order representation of the address. const char* V4STRING = "192.0.2.1"; uint8_t V4[] = {0xc0, 0x00, 0x02, 0x01}; std::vector actual = IOAddress(V4STRING).toBytes(); ASSERT_EQ(sizeof(V4), actual.size()); EXPECT_TRUE(std::equal(actual.begin(), actual.end(), V4)); } TEST(IOAddressTest, toBytesV6) { // Address and network byte-order representation of the address. const char* V6STRING = "2001:db8:1::dead:beef"; uint8_t V6[] = { 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0xad, 0xbe, 0xef }; std::vector actual = IOAddress(V6STRING).toBytes(); ASSERT_EQ(sizeof(V6), actual.size()); EXPECT_TRUE(std::equal(actual.begin(), actual.end(), V6)); } TEST(IOAddressTest, isV4) { const IOAddress address4("192.0.2.1"); const IOAddress address6("2001:db8:1::dead:beef"); EXPECT_TRUE(address4.isV4()); EXPECT_FALSE(address6.isV4()); } TEST(IOAddressTest, isV4Zero) { // 0.0.0.0 const IOAddress address_zero("0.0.0.0"); EXPECT_TRUE(address_zero.isV4Zero()); // :: (v6 zero address) const IOAddress address_zero_v6("::"); EXPECT_FALSE(address_zero_v6.isV4Zero()); // 192.0.2.3 const IOAddress address_non_zero("192.0.2.3"); EXPECT_FALSE(address_non_zero.isV4Zero()); // 0.0.0.100 const IOAddress address_non_zero1("0.0.0.100"); EXPECT_FALSE(address_non_zero1.isV4Zero()); // 64.0.0.0 const IOAddress address_non_zero2("64.0.0.0"); EXPECT_FALSE(address_non_zero2.isV4Zero()); } TEST(IOAddressTest, isV4Bcast) { // 255.255.255.255 const IOAddress address_bcast("255.255.255.255"); EXPECT_TRUE(address_bcast.isV4Bcast()); // 10.2.3.4 const IOAddress address_non_bcast("10.2.3.4"); EXPECT_FALSE(address_non_bcast.isV4Bcast()); // 255.255.255.23 const IOAddress address_non_bcast1("255.255.255.23"); EXPECT_FALSE(address_non_bcast1.isV4Bcast()); // 123.255.255.255 const IOAddress address_non_bcast2("123.255.255.255"); EXPECT_FALSE(address_non_bcast2.isV4Bcast()); } TEST(IOAddressTest, isV6) { const IOAddress address4("192.0.2.1"); const IOAddress address6("2001:db8:1::dead:beef"); EXPECT_FALSE(address4.isV6()); EXPECT_TRUE(address6.isV6()); } TEST(IOAddressTest, isV6Zero) { // :: const IOAddress address_zero("::"); EXPECT_TRUE(address_zero.isV6Zero()); // 0.0.0.0 const IOAddress address_non_zero("0.0.0.0"); EXPECT_FALSE(address_non_zero.isV6Zero()); // ::ff const IOAddress address_non_zero1("::ff"); EXPECT_FALSE(address_non_zero1.isV6Zero()); // ff:: const IOAddress address_non_zero2("ff::"); EXPECT_FALSE(address_non_zero2.isV6Zero()); } TEST(IOAddressTest, uint32) { IOAddress addr1("192.0.2.5"); // operator uint_32() is used here uint32_t tmp = addr1.toUint32(); uint32_t expected = (192U << 24) + (0U << 16) + (2U << 8) + 5U; EXPECT_EQ(expected, tmp); // now let's try opposite conversion IOAddress addr3 = IOAddress(expected); EXPECT_EQ(addr3.toText(), "192.0.2.5"); } TEST(IOAddressTest, lessThanEqual) { IOAddress addr1("192.0.2.5"); IOAddress addr2("192.0.2.6"); IOAddress addr3("0.0.0.0"); IOAddress addr4("::"); IOAddress addr5("2001:db8::1"); IOAddress addr6("2001:db8::1:0"); IOAddress addr7("2001:db8::1:0"); // the same as 6 // v4 comparisons EXPECT_TRUE(addr1 < addr2); EXPECT_FALSE(addr2 < addr1); EXPECT_FALSE(addr2 <= addr1); EXPECT_TRUE(addr3 < addr1); EXPECT_TRUE(addr3 < addr2); EXPECT_TRUE(addr3 <= addr2); // v6 comparisons EXPECT_TRUE(addr4 < addr5); EXPECT_TRUE(addr5 < addr6); EXPECT_FALSE(addr6 < addr5); EXPECT_FALSE(addr6 <= addr5); // v4 to v6 - v4 should always be smaller EXPECT_TRUE(addr1 < addr4); EXPECT_TRUE(addr3 < addr4); EXPECT_TRUE(addr2 < addr5); EXPECT_TRUE(addr6 <= addr7); } // test operator<<. We simply confirm it appends the result of toText(). TEST(IOAddressTest, LeftShiftOperator) { const IOAddress addr("192.0.2.5"); std::ostringstream oss; oss << addr; EXPECT_EQ(addr.toText(), oss.str()); } // Tests address classification methods (which were previously used by accessing // underlying asio objects directly) TEST(IOAddressTest, accessClassificationMethods) { IOAddress addr1("192.0.2.5"); // IPv4 IOAddress addr2("::"); // IPv6 IOAddress addr3("2001:db8::1"); // global IPv6 IOAddress addr4("fe80::1234"); // link-local IOAddress addr5("ff02::1:2"); // multicast EXPECT_TRUE (addr1.isV4()); EXPECT_FALSE(addr1.isV6()); EXPECT_FALSE(addr1.isV6LinkLocal()); EXPECT_FALSE(addr1.isV6Multicast()); EXPECT_FALSE(addr2.isV4()); EXPECT_TRUE (addr2.isV6()); EXPECT_FALSE(addr2.isV6LinkLocal()); EXPECT_FALSE(addr2.isV6Multicast()); EXPECT_FALSE(addr3.isV4()); EXPECT_TRUE (addr3.isV6()); EXPECT_FALSE(addr3.isV6LinkLocal()); EXPECT_FALSE(addr3.isV6Multicast()); EXPECT_FALSE(addr4.isV4()); EXPECT_TRUE (addr4.isV6()); EXPECT_TRUE (addr4.isV6LinkLocal()); EXPECT_FALSE(addr4.isV6Multicast()); EXPECT_FALSE(addr5.isV4()); EXPECT_TRUE (addr5.isV6()); EXPECT_FALSE(addr5.isV6LinkLocal()); EXPECT_TRUE (addr5.isV6Multicast()); } TEST(IOAddressTest, staticAddresses) { EXPECT_EQ(IOAddress("0.0.0.0"), IOAddress::IPV4_ZERO_ADDRESS()); EXPECT_EQ(IOAddress("255.255.255.255"), IOAddress::IPV4_BCAST_ADDRESS()); EXPECT_EQ(IOAddress("::"), IOAddress::IPV6_ZERO_ADDRESS()); } // Tests whether address subtraction works correctly. TEST(IOAddressTest, subtract) { IOAddress addr1("192.0.2.12"); IOAddress addr2("192.0.2.5"); IOAddress addr3("192.0.2.0"); IOAddress addr4("0.0.2.1"); IOAddress any4("0.0.0.0"); IOAddress bcast("255.255.255.255"); EXPECT_EQ("0.0.0.7", IOAddress::subtract(addr1, addr2).toText()); EXPECT_EQ("0.0.0.12", IOAddress::subtract(addr1, addr3).toText()); // Subtracting 0.0.0.0 is like subtracting 0. EXPECT_EQ("192.0.2.12", IOAddress::subtract(addr1, any4).toText()); EXPECT_EQ("192.0.2.13", IOAddress::subtract(addr1, bcast).toText()); EXPECT_EQ("191.255.255.255", IOAddress::subtract(addr3, addr4).toText()); // Let's check if we can subtract greater address from smaller. // This will check if we can "loop" EXPECT_EQ("255.255.255.251", IOAddress::subtract(addr3, addr2).toText()); IOAddress addr6("fe80::abcd"); IOAddress addr7("fe80::"); IOAddress addr8("fe80::1234"); IOAddress addr9("2001:db8::face"); IOAddress addr10("2001:db8::ffff:ffff:ffff:ffff"); IOAddress addr11("::1"); IOAddress any6("::"); EXPECT_EQ(IOAddress("::abcd"), IOAddress::subtract(addr6, addr7)); EXPECT_EQ(IOAddress("::9999"), IOAddress::subtract(addr6, addr8)); EXPECT_EQ("::ffff:ffff:ffff:531", IOAddress::subtract(addr10, addr9).toText()); // Subtract with borrow, extreme edition. Need to borrow one bit // 112 times. EXPECT_EQ("fe7f:ffff:ffff:ffff:ffff:ffff:ffff:ffff", IOAddress::subtract(addr7, addr11).toText()); // Now check if we can loop beyond :: (:: - ::1 is a lot of F's) EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", IOAddress::subtract(any6, addr11).toText()); // Subtracting :: is like subtracting 0. EXPECT_EQ("2001:db8::face", IOAddress::subtract(addr9, any6).toText()); // Let's check if we can subtract greater address from smaller. // This will check if we can "loop" EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:edcc", IOAddress::subtract(addr7, addr8).toText()); // Inter-family relations are not allowed. EXPECT_THROW(IOAddress::subtract(addr1, addr6), isc::BadValue); EXPECT_THROW(IOAddress::subtract(addr6, addr1), isc::BadValue); } // Test checks whether an address can be increased. TEST(IOAddressTest, increaseAddr) { IOAddress addr1("192.0.2.12"); IOAddress any4("0.0.0.0"); IOAddress bcast("255.255.255.255"); IOAddress addr6("2001:db8::ffff:ffff:ffff:ffff"); IOAddress addr11("::1"); IOAddress any6("::"); IOAddress the_last_one("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"); EXPECT_EQ("192.0.2.13", IOAddress::increase(addr1).toText()); EXPECT_EQ("0.0.0.1", IOAddress::increase(any4).toText()); EXPECT_EQ("0.0.0.0", IOAddress::increase(bcast).toText()); EXPECT_EQ("2001:db8:0:1::", IOAddress::increase(addr6).toText()); EXPECT_EQ(IOAddress("::2"), IOAddress::increase(addr11)); EXPECT_EQ(IOAddress("::1"), IOAddress::increase(any6)); EXPECT_EQ(IOAddress("::"), IOAddress::increase(the_last_one)); } kea-1.1.0/src/lib/asiolink/tests/tcp_socket_unittest.cc0000664000175000017500000004651012772017075020126 00000000000000// Copyright (C) 2011-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/. /// \brief Test of TCPSocket /// /// Tests the functionality of a TCPSocket by working through an open-send- /// receive-close sequence and checking that the asynchronous notifications /// work. #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace boost::asio; using namespace boost::asio::ip; using namespace isc::util; using namespace isc::asiolink; using namespace std; namespace { const char SERVER_ADDRESS[] = "127.0.0.1"; const unsigned short SERVER_PORT = 5303; // TODO: Shouldn't we send something that is real message? const char OUTBOUND_DATA[] = "Data sent from client to server"; const char INBOUND_DATA[] = "Returned data from server to client"; } /// An instance of this object is passed to the asynchronous I/O functions /// and the operator() method is called when when an asynchronous I/O completes. /// The arguments to the completion callback are stored for later retrieval. class TCPCallback { public: /// \brief Operations the server is doing enum Operation { ACCEPT = 0, ///< accept() was issued OPEN = 1, /// Client connected to server READ = 2, ///< Asynchronous read completed WRITE = 3, ///< Asynchronous write completed NONE = 4 ///< "Not set" state }; /// \brief Minimim size of buffers enum { MIN_SIZE = (64 * 1024 + 2) ///< 64kB + two bytes for a count }; struct PrivateData { PrivateData() : error_code_(), length_(0), cumulative_(0), expected_(0), offset_(0), name_(""), queued_(NONE), called_(NONE), data_(MIN_SIZE, 0) {} boost::system::error_code error_code_; ///< Completion error code size_t length_; ///< Bytes transferred in this I/O size_t cumulative_; ///< Cumulative bytes transferred size_t expected_; ///< Expected amount of data size_t offset_; ///< Where to put data in buffer std::string name_; ///< Which of the objects this is Operation queued_; ///< Queued operation Operation called_; ///< Which callback called std::vector data_; ///< Receive buffer }; /// \brief Constructor /// /// Constructs the object. It also creates the data member pointed to by /// a shared pointer. When used as a callback object, this is copied as it /// is passed into the asynchronous function. This means that there are two /// objects and inspecting the one we passed in does not tell us anything. /// /// Therefore we use a boost::shared_ptr. When the object is copied, the /// shared pointer is copied, which leaves both objects pointing to the same /// data. /// /// \param which Which of the two callback objects this is TCPCallback(std::string which) : ptr_(new PrivateData()) { ptr_->name_ = which; } /// \brief Destructor /// /// No code needed, destroying the shared pointer destroys the private data. virtual ~TCPCallback() {} /// \brief Client Callback Function /// /// Called when an asynchronous operation is completed by the client, this /// stores the origin of the operation in the client_called_ data member. /// /// \param ec I/O completion error code passed to callback function. /// \param length Number of bytes transferred void operator()(boost::system::error_code ec = boost::system::error_code(), size_t length = 0) { setCode(ec.value()); ptr_->called_ = ptr_->queued_; ptr_->length_ = length; } /// \brief Get I/O completion error code int getCode() { return (ptr_->error_code_.value()); } /// \brief Set I/O completion code /// /// \param code New value of completion code void setCode(int code) { ptr_->error_code_ = boost::system::error_code(code, boost::system::error_code().category()); } /// \brief Get number of bytes transferred in I/O size_t& length() { return (ptr_->length_); } /// \brief Get cumulative number of bytes transferred in I/O size_t& cumulative() { return (ptr_->cumulative_); } /// \brief Get expected amount of data size_t& expected() { return (ptr_->expected_); } /// \brief Get offset intodData size_t& offset() { return (ptr_->offset_); } /// \brief Get data member uint8_t* data() { return (&ptr_->data_[0]); } /// \brief Get flag to say what was queued Operation& queued() { return (ptr_->queued_); } /// \brief Get flag to say when callback was called Operation& called() { return (ptr_->called_); } /// \brief Return instance of callback name std::string& name() { return (ptr_->name_); } private: boost::shared_ptr ptr_; ///< Pointer to private data }; // Read Server Data // // Called in the part of the test that has the client send a message to the // server, this loops until all the data has been read (synchronously) by the // server. // // "All the data read" means that the server has received a message that is // preceded by a two-byte count field and that the total amount of data received // from the remote end is equal to the value in the count field plus two bytes // for the count field itself. // // \param socket Socket on which the server is reading data // \param server_cb Structure in which server data is held. void serverRead(tcp::socket& socket, TCPCallback& server_cb) { // As we may need to read multiple times, keep a count of the cumulative // amount of data read and do successive reads into the appropriate part // of the buffer. // // Note that there are no checks for buffer overflow - this is a test // program and we have sized the buffer to be large enough for the test. server_cb.cumulative() = 0; bool complete = false; while (!complete) { // Read block of data and update cumulative amount of data received. server_cb.length() = socket.receive( boost::asio::buffer(server_cb.data() + server_cb.cumulative(), TCPCallback::MIN_SIZE - server_cb.cumulative())); server_cb.cumulative() += server_cb.length(); // If we have read at least two bytes, we can work out how much we // should be reading. if (server_cb.cumulative() >= 2) { server_cb.expected() = readUint16(server_cb.data(), server_cb.length()); if ((server_cb.expected() + 2) == server_cb.cumulative()) { // Amount of data read from socket equals the size of the // message (as indicated in the first two bytes of the message) // plus the size of the count field. Therefore we have received // all the data. complete = true; } } } } // Receive complete method should return true only if the count in the first // two bytes is equal to the size of the rest if the buffer. TEST(TCPSocket, processReceivedData) { const uint16_t PACKET_SIZE = 16382; // Amount of "real" data in the buffer IOService service; // Used to instantiate socket TCPSocket test(service); // Socket under test uint8_t inbuff[PACKET_SIZE + 2]; // Buffer to check OutputBufferPtr outbuff(new OutputBuffer(16)); // Where data is put size_t expected; // Expected amount of data size_t offset; // Where to put next data size_t cumulative; // Cumulative data received // Set some dummy values in the buffer to check for (size_t i = 0; i < sizeof(inbuff); ++i) { inbuff[i] = i % 256; } // Check that the method will handle various receive sizes. writeUint16(PACKET_SIZE, inbuff, sizeof(inbuff)); cumulative = 0; offset = 0; expected = 0; outbuff->clear(); bool complete = test.processReceivedData(inbuff, 1, cumulative, offset, expected, outbuff); EXPECT_FALSE(complete); EXPECT_EQ(1, cumulative); EXPECT_EQ(1, offset); EXPECT_EQ(0, expected); EXPECT_EQ(0, outbuff->getLength()); // Now pretend that we've received one more byte. complete = test.processReceivedData(inbuff, 1, cumulative, offset, expected, outbuff); EXPECT_FALSE(complete); EXPECT_EQ(2, cumulative); EXPECT_EQ(0, offset); EXPECT_EQ(PACKET_SIZE, expected); EXPECT_EQ(0, outbuff->getLength()); // Add another two bytes. However, this time note that we have to offset // in the input buffer because it is expected that the next chunk of data // from the connection will be read into the start of the buffer. complete = test.processReceivedData(inbuff + cumulative, 2, cumulative, offset, expected, outbuff); EXPECT_FALSE(complete); EXPECT_EQ(4, cumulative); EXPECT_EQ(0, offset); EXPECT_EQ(PACKET_SIZE, expected); EXPECT_EQ(2, outbuff->getLength()); const uint8_t* dataptr = static_cast(outbuff->getData()); EXPECT_TRUE(equal(inbuff + 2, inbuff + cumulative, dataptr)); // And add the remaining data. Remember that "inbuff" is "PACKET_SIZE + 2" // long. complete = test.processReceivedData(inbuff + cumulative, PACKET_SIZE + 2 - cumulative, cumulative, offset, expected, outbuff); EXPECT_TRUE(complete); EXPECT_EQ(PACKET_SIZE + 2, cumulative); EXPECT_EQ(0, offset); EXPECT_EQ(PACKET_SIZE, expected); EXPECT_EQ(PACKET_SIZE, outbuff->getLength()); dataptr = static_cast(outbuff->getData()); EXPECT_TRUE(equal(inbuff + 2, inbuff + cumulative, dataptr)); } // TODO: Need to add a test to check the cancel() method // Tests the operation of a TCPSocket by opening it, sending an asynchronous // message to a server, receiving an asynchronous message from the server and // closing. TEST(TCPSocket, sequenceTest) { // Common objects. IOService service; // Service object for async control // The client - the TCPSocket being tested TCPSocket client(service);// Socket under test TCPCallback client_cb("Client"); // Async I/O callback function TCPEndpoint client_remote_endpoint; // Where client receives message from OutputBufferPtr client_buffer(new OutputBuffer(128)); // Received data is put here // The server - with which the client communicates. IOAddress server_address(SERVER_ADDRESS); // Address of target server TCPCallback server_cb("Server"); // Server callback TCPEndpoint server_endpoint(server_address, SERVER_PORT); // Endpoint describing server TCPEndpoint server_remote_endpoint; // Address where server received message from tcp::socket server_socket(service.get_io_service()); // Socket used for server // Step 1. Create the connection between the client and the server. Set // up the server to accept incoming connections and have the client open // a channel to it. // Set up server - open socket and queue an accept. server_cb.queued() = TCPCallback::ACCEPT; server_cb.called() = TCPCallback::NONE; server_cb.setCode(42); // Some error tcp::acceptor acceptor(service.get_io_service(), tcp::endpoint(tcp::v4(), SERVER_PORT)); acceptor.set_option(tcp::acceptor::reuse_address(true)); acceptor.async_accept(server_socket, server_cb); // Set up client - connect to the server. client_cb.queued() = TCPCallback::OPEN; client_cb.called() = TCPCallback::NONE; client_cb.setCode(43); // Some error EXPECT_FALSE(client.isOpenSynchronous()); client.open(&server_endpoint, client_cb); // Run the open and the accept callback and check that they ran. service.run_one(); service.run_one(); EXPECT_EQ(TCPCallback::ACCEPT, server_cb.called()); EXPECT_EQ(0, server_cb.getCode()); EXPECT_EQ(TCPCallback::OPEN, client_cb.called()); EXPECT_EQ(0, client_cb.getCode()); // Step 2. Get the client to write to the server asynchronously. The // server will loop reading the data synchronously. // Write asynchronously to the server. client_cb.called() = TCPCallback::NONE; client_cb.queued() = TCPCallback::WRITE; client_cb.setCode(143); // Arbitrary number client_cb.length() = 0; client.asyncSend(OUTBOUND_DATA, sizeof(OUTBOUND_DATA), &server_endpoint, client_cb); // Wait for the client callback to complete. (Must do this first on // Solaris: if we do the synchronous read first, the test hangs.) service.run_one(); // Synchronously read the data from the server.; serverRead(server_socket, server_cb); // Check the client state EXPECT_EQ(TCPCallback::WRITE, client_cb.called()); EXPECT_EQ(0, client_cb.getCode()); EXPECT_EQ(sizeof(OUTBOUND_DATA) + 2, client_cb.length()); // ... and check what the server received. EXPECT_EQ(sizeof(OUTBOUND_DATA) + 2, server_cb.cumulative()); EXPECT_TRUE(equal(OUTBOUND_DATA, (OUTBOUND_DATA + (sizeof(OUTBOUND_DATA) - 1)), (server_cb.data() + 2))); // Step 3. Get the server to write all the data asynchronously and have the // client loop (asynchronously) reading the data. Note that we copy the // data into the server's internal buffer in order to precede it with a two- // byte count field. // Have the server write asynchronously to the client. server_cb.called() = TCPCallback::NONE; server_cb.queued() = TCPCallback::WRITE; server_cb.length() = 0; server_cb.cumulative() = 0; writeUint16(sizeof(INBOUND_DATA), server_cb.data(), TCPCallback::MIN_SIZE); copy(INBOUND_DATA, (INBOUND_DATA + sizeof(INBOUND_DATA) - 1), (server_cb.data() + 2)); server_socket.async_send(boost::asio::buffer(server_cb.data(), (sizeof(INBOUND_DATA) + 2)), server_cb); // Have the client read asynchronously. client_cb.called() = TCPCallback::NONE; client_cb.queued() = TCPCallback::READ; client_cb.length() = 0; client_cb.cumulative() = 0; client_cb.expected() = 0; client_cb.offset() = 0; client.asyncReceive(client_cb.data(), TCPCallback::MIN_SIZE, client_cb.offset(), &client_remote_endpoint, client_cb); // Run the callbacks. Several options are possible depending on how ASIO // is implemented and whether the message gets fragmented: // // 1) The send handler may complete immediately, regardess of whether the // data has been read by the client. (This is the most likely.) // 2) The send handler may only run after all the data has been read by // the client. (This could happen if the client's TCP buffers were too // small so the data was not transferred to the "remote" system until the // remote buffer has been emptied one or more times.) // 3) The client handler may be run a number of times to handle the message // fragments and the server handler may run between calls of the client // handler. // // So loop, running one handler at a time until we are certain that all the // handlers have run. bool server_complete = false; bool client_complete = false; while (!server_complete || !client_complete) { service.run_one(); // Has the server run? if (!server_complete) { if (server_cb.called() == server_cb.queued()) { // Yes. Check that the send completed successfully and that // all the data that was expected to have been sent was in fact // sent. EXPECT_EQ(0, server_cb.getCode()); EXPECT_EQ((sizeof(INBOUND_DATA) + 2), server_cb.length()); server_complete = true; } } // Has the client run? if (!client_complete) { if (client_cb.called() != client_cb.queued()) { // No. Run the service another time. continue; } // Client callback must have run. Check that it ran OK. EXPECT_EQ(TCPCallback::READ, client_cb.called()); EXPECT_EQ(0, client_cb.getCode()); // Check if we need to queue another read, copying the data into // the output buffer as we do so. client_complete = client.processReceivedData(client_cb.data(), client_cb.length(), client_cb.cumulative(), client_cb.offset(), client_cb.expected(), client_buffer); // If the data is not complete, queue another read. if (! client_complete) { client_cb.called() = TCPCallback::NONE; client_cb.queued() = TCPCallback::READ; client_cb.length() = 0; client.asyncReceive(client_cb.data(), TCPCallback::MIN_SIZE , client_cb.offset(), &client_remote_endpoint, client_cb); } } } // Both the send and the receive have completed. Check that the received // is what was sent. // Check the client state EXPECT_EQ(TCPCallback::READ, client_cb.called()); EXPECT_EQ(0, client_cb.getCode()); EXPECT_EQ(sizeof(INBOUND_DATA) + 2, client_cb.cumulative()); EXPECT_EQ(sizeof(INBOUND_DATA), client_buffer->getLength()); // ... and check what the server sent. EXPECT_EQ(TCPCallback::WRITE, server_cb.called()); EXPECT_EQ(0, server_cb.getCode()); EXPECT_EQ(sizeof(INBOUND_DATA) + 2, server_cb.length()); // ... and that what was sent is what was received. const uint8_t* received = static_cast(client_buffer->getData()); EXPECT_TRUE(equal(INBOUND_DATA, (INBOUND_DATA + (sizeof(INBOUND_DATA) - 1)), received)); // Close client and server. EXPECT_NO_THROW(client.close()); EXPECT_NO_THROW(server_socket.close()); } kea-1.1.0/src/lib/asiolink/tests/interval_timer_unittest.cc0000664000175000017500000003375512772017075021023 00000000000000// Copyright (C) 2011-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 #include #include #include #include namespace { // TODO: Consider this margin const boost::posix_time::time_duration TIMER_MARGIN_MSEC = boost::posix_time::milliseconds(50); } using namespace isc::asiolink; // This fixture is for testing IntervalTimer. Some callback functors are // registered as callback function of the timer to test if they are called // or not. class IntervalTimerTest : public ::testing::Test { protected: IntervalTimerTest() : io_service_(), timer_called_(false), timer_cancel_success_(false) {} ~IntervalTimerTest() {} class TimerCallBack : public std::unary_function { public: TimerCallBack(IntervalTimerTest* test_obj) : test_obj_(test_obj) {} void operator()() const { test_obj_->timer_called_ = true; test_obj_->io_service_.stop(); return; } private: IntervalTimerTest* test_obj_; }; class TimerCallBackCounter : public std::unary_function { public: TimerCallBackCounter(IntervalTimerTest* test_obj) : test_obj_(test_obj) { counter_ = 0; } void operator()() { ++counter_; return; } int counter_; private: IntervalTimerTest* test_obj_; }; class TimerCallBackCancelDeleter : public std::unary_function { public: TimerCallBackCancelDeleter(IntervalTimerTest* test_obj, IntervalTimer* timer, TimerCallBackCounter& counter) : test_obj_(test_obj), timer_(timer), counter_(counter), count_(0), prev_counter_(-1) {} void operator()() { ++count_; if (count_ == 1) { // First time of call back. // Store the value of counter_.counter_. prev_counter_ = counter_.counter_; delete timer_; } else if (count_ == 2) { // Second time of call back. // Stop io_service to stop all timers. test_obj_->io_service_.stop(); // Compare the value of counter_.counter_ with stored one. // If TimerCallBackCounter was not called (expected behavior), // they are same. if (counter_.counter_ == prev_counter_) { test_obj_->timer_cancel_success_ = true; } } return; } private: IntervalTimerTest* test_obj_; IntervalTimer* timer_; TimerCallBackCounter& counter_; int count_; int prev_counter_; }; class TimerCallBackCanceller { public: TimerCallBackCanceller(unsigned int& counter, IntervalTimer& itimer) : counter_(counter), itimer_(itimer) {} void operator()() { ++counter_; itimer_.cancel(); } private: unsigned int& counter_; IntervalTimer& itimer_; }; class TimerCallBackOverwriter : public std::unary_function { public: TimerCallBackOverwriter(IntervalTimerTest* test_obj, IntervalTimer& timer) : test_obj_(test_obj), timer_(timer), count_(0) {} void operator()() { ++count_; if (count_ == 1) { // First time of call back. // Call setup() to update callback function to TimerCallBack. test_obj_->timer_called_ = false; timer_.setup(TimerCallBack(test_obj_), 100); } else if (count_ == 2) { // Second time of call back. // If it reaches here, re-setup() is failed (unexpected). // We should stop here. test_obj_->io_service_.stop(); } return; } private: IntervalTimerTest* test_obj_; IntervalTimer& timer_; int count_; }; class TimerCallBackAccumulator: public std::unary_function { public: TimerCallBackAccumulator(IntervalTimerTest* test_obj, int &counter) : test_obj_(test_obj), counter_(counter) { } void operator()() { ++counter_; return; } private: IntervalTimerTest* test_obj_; // Reference to integer accumulator int& counter_; }; protected: IOService io_service_; bool timer_called_; bool timer_cancel_success_; }; TEST_F(IntervalTimerTest, invalidArgumentToIntervalTimer) { // Create asio_link::IntervalTimer and setup. IntervalTimer itimer(io_service_); // expect throw if call back function is empty EXPECT_THROW(itimer.setup(IntervalTimer::Callback(), 1), isc::InvalidParameter); // expect throw if interval is not greater than 0 EXPECT_THROW(itimer.setup(TimerCallBack(this), 0), isc::BadValue); EXPECT_THROW(itimer.setup(TimerCallBack(this), -1), isc::BadValue); } TEST_F(IntervalTimerTest, startIntervalTimer) { // Create asio_link::IntervalTimer and setup. // Then run IOService and test if the callback function is called. IntervalTimer itimer(io_service_); timer_called_ = false; // store start time boost::posix_time::ptime start; start = boost::posix_time::microsec_clock::universal_time(); // setup timer itimer.setup(TimerCallBack(this), 100); EXPECT_EQ(100, itimer.getInterval()); io_service_.run(); // Control reaches here after io_service_ was stopped by TimerCallBack. // delta: difference between elapsed time and 100 milliseconds. boost::posix_time::time_duration test_runtime = boost::posix_time::microsec_clock::universal_time() - start; EXPECT_FALSE(test_runtime.is_negative()) << "test duration " << test_runtime << " negative - clock skew?"; // Expect TimerCallBack is called; timer_called_ is true EXPECT_TRUE(timer_called_); // Expect test_runtime is 100 milliseconds or longer. // Allow 1% of clock skew EXPECT_TRUE(test_runtime >= boost::posix_time::milliseconds(99)) << "test runtime " << test_runtime.total_milliseconds() << "msec " << ">= 100"; } TEST_F(IntervalTimerTest, destructIntervalTimer) { // This code isn't exception safe, but we'd rather keep the code // simpler and more readable as this is only for tests and if it throws // the program would immediately terminate anyway. // The call back function will not be called after the timer is // destroyed. // // There are two timers: // itimer_counter (A) // (Calls TimerCallBackCounter) // - increments internal counter in callback function // itimer_canceller (B) // (Calls TimerCallBackCancelDeleter) // - first time of callback, it stores the counter value of // callback_canceller and destroys itimer_counter // - second time of callback, it compares the counter value of // callback_canceller with stored value // if they are same the timer was not called; expected result // if they are different the timer was called after destroyed // // 0 100 200 300 400 500 600 (ms) // (A) i--------+----x // ^ // |destroy itimer_counter // (B) i-------------+--------------s // ^stop io_service // and check if itimer_counter have been // stopped // itimer_counter will be deleted in TimerCallBackCancelDeleter IntervalTimer* itimer_counter = new IntervalTimer(io_service_); IntervalTimer itimer_canceller(io_service_); timer_cancel_success_ = false; TimerCallBackCounter callback_canceller(this); itimer_counter->setup(callback_canceller, 200); itimer_canceller.setup( TimerCallBackCancelDeleter(this, itimer_counter, callback_canceller), 300); io_service_.run(); EXPECT_TRUE(timer_cancel_success_); } TEST_F(IntervalTimerTest, cancel) { // Similar to destructIntervalTimer test, but the first timer explicitly // cancels itself on first callback. IntervalTimer itimer_counter(io_service_); IntervalTimer itimer_watcher(io_service_); unsigned int counter = 0; itimer_counter.setup(TimerCallBackCanceller(counter, itimer_counter), 100); itimer_watcher.setup(TimerCallBack(this), 200); io_service_.run(); EXPECT_EQ(1, counter); EXPECT_EQ(0, itimer_counter.getInterval()); // canceling an already canceled timer shouldn't cause any surprise. EXPECT_NO_THROW(itimer_counter.cancel()); } TEST_F(IntervalTimerTest, overwriteIntervalTimer) { // Call setup() multiple times to update call back function and interval. // // There are two timers: // itimer (A) // (Calls TimerCallBackCounter / TimerCallBack) // - increments internal counter in callback function // (TimerCallBackCounter) // interval: 300 milliseconds // - io_service_.stop() (TimerCallBack) // interval: 100 milliseconds // itimer_overwriter (B) // (Calls TimerCallBackOverwriter) // - first time of callback, it calls setup() to change call back // function to TimerCallBack and interval of itimer to 100 // milliseconds // after 300 + 100 milliseconds from the beginning of this test, // TimerCallBack() will be called and io_service_ stops. // - second time of callback, it means the test fails. // // 0 100 200 300 400 500 600 700 800 (ms) // (A) i-------------+----C----s // ^ ^stop io_service // |change call back function and interval // (B) i------------------+-------------------S // ^(stop io_service on fail) // IntervalTimer itimer(io_service_); IntervalTimer itimer_overwriter(io_service_); // store start time boost::posix_time::ptime start; start = boost::posix_time::microsec_clock::universal_time(); itimer.setup(TimerCallBackCounter(this), 300); itimer_overwriter.setup(TimerCallBackOverwriter(this, itimer), 400); io_service_.run(); // Control reaches here after io_service_ was stopped by // TimerCallBackCounter or TimerCallBackOverwriter. // Expect callback function is updated: TimerCallBack is called EXPECT_TRUE(timer_called_); // Expect interval is updated: return value of getInterval() is updated EXPECT_EQ(itimer.getInterval(), 100); } // This test verifies that timers operate correctly based on their mode. TEST_F(IntervalTimerTest, intervalModeTest) { // Create a timer to control the duration of the test. IntervalTimer test_timer(io_service_); test_timer.setup(TimerCallBack(this), 2000); // Create an timer which automatically reschedules itself. Use the // accumulator callback to increment local counter for it. int repeater_count = 0; IntervalTimer repeater(io_service_); repeater.setup(TimerCallBackAccumulator(this, repeater_count), 10); // Create a one-shot timer. Use the accumulator callback to increment // local counter variable for it. int one_shot_count = 0; IntervalTimer one_shot(io_service_); one_shot.setup(TimerCallBackAccumulator(this, one_shot_count), 10, IntervalTimer::ONE_SHOT); // As long as service runs at least one event handler, loop until // we've hit our goals. It won't return zero unless is out of // work or the the service has been stopped by the test timer. int cnt = 0; while (((cnt = io_service_.get_io_service().run_one()) > 0) && (repeater_count < 5)) { // deliberately empty }; // If cnt is zero, then something went wrong. EXPECT_TRUE(cnt > 0); // The loop stopped make sure it was for the right reason. EXPECT_EQ(repeater_count, 5); EXPECT_EQ(one_shot_count, 1); } // This test verifies that the same timer can be reused in either mode. TEST_F(IntervalTimerTest, timerReuseTest) { // Create a timer to control the duration of the test. IntervalTimer test_timer(io_service_); test_timer.setup(TimerCallBack(this), 2000); // Create a one-shot timer. Use the accumulator callback to increment // local counter variable for it. int one_shot_count = 0; IntervalTimer one_shot(io_service_); TimerCallBackAccumulator callback(this, one_shot_count); one_shot.setup(callback, 10, IntervalTimer::ONE_SHOT); // Run until a single event handler executes. This should be our // one-shot expiring. io_service_.run_one(); // Verify the timer expired once. ASSERT_EQ(one_shot_count, 1); // Setup the one-shot to go again. one_shot.setup(callback, 10, IntervalTimer::ONE_SHOT); // Run until a single event handler executes. This should be our // one-shot expiring. io_service_.run_one(); // Verify the timer expired once. ASSERT_EQ(one_shot_count, 2); // Setup the timer to be repeating. one_shot.setup(callback, 10, IntervalTimer::REPEATING); // As long as service runs at least one event handler, loop until // we've hit our goals. It won't return zero unless is out of // work or the the service has been stopped by the test timer. int cnt = 0; while ((cnt = io_service_.get_io_service().run_one()) && (one_shot_count < 4)) { // deliberately empty }; // If cnt is zero, then something went wrong. EXPECT_TRUE(cnt > 0); // Verify the timer repeated. EXPECT_GE(one_shot_count, 4); } kea-1.1.0/src/lib/asiolink/io_socket.cc0000664000175000017500000000344412772017075014645 00000000000000// Copyright (C) 2010-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 #include #include namespace isc { namespace asiolink { /// \brief The \c DummySocket class is a concrete derived class of /// \c IOSocket that is not associated with any real socket. /// /// This main purpose of this class is tests, where it may be desirable to /// instantiate an \c IOSocket object without involving system resource /// allocation such as real network sockets. class DummySocket : public IOSocket { private: DummySocket(const DummySocket& source); DummySocket& operator=(const DummySocket& source); public: /// \brief Constructor from the protocol number. /// /// The protocol must validly identify a standard network protocol. /// For example, to specify TCP \c protocol must be \c IPPROTO_TCP. /// /// \param protocol The network protocol number for the socket. DummySocket(const int protocol) : protocol_(protocol) {} /// \brief A dummy derived method of \c IOSocket::getNative(). /// /// This version of method always returns -1 as the object is not /// associated with a real (native) socket. virtual int getNative() const { return (-1); } virtual int getProtocol() const { return (protocol_); } private: const int protocol_; }; IOSocket& IOSocket::getDummyUDPSocket() { static DummySocket socket(IPPROTO_UDP); return (socket); } IOSocket& IOSocket::getDummyTCPSocket() { static DummySocket socket(IPPROTO_TCP); return (socket); } } // namespace asiolink } // namespace isc kea-1.1.0/src/lib/asiolink/io_socket.h0000664000175000017500000001055612772017075014511 00000000000000// Copyright (C) 2010-2015 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 IO_SOCKET_H #define IO_SOCKET_H 1 // IMPORTANT NOTE: only very few ASIO headers files can be included in // this file. In particular, asio.hpp should never be included here. // See the description of the namespace below. #include // for some network system calls #include #include #include namespace isc { namespace asiolink { /// \brief The \c IOSocket class is an abstract base class to represent /// various types of network sockets. /// /// This class is a wrapper for the ASIO socket classes such as /// \c ip::tcp::socket and \c ip::udp::socket. /// /// Derived class implementations are completely hidden within the /// implementation. User applications only get access to concrete /// \c IOSocket objects via the abstract interfaces. /// /// We may revisit this decision when we generalize the wrapper and more /// modules use it. Also, at that point we may define a separate (visible) /// derived class for testing purposes rather than providing factory methods /// (i.e., getDummy variants below). class IOSocket { /// /// \name Constructors and Destructor /// /// Note: The copy constructor and the assignment operator are /// intentionally defined as private, making this class non-copyable. //@{ private: IOSocket(const IOSocket& source); IOSocket& operator=(const IOSocket& source); protected: /// \brief The default constructor. /// /// This is intentionally defined as \c protected as this base class /// should never be instantiated (except as part of a derived class). IOSocket() {} public: /// The destructor. virtual ~IOSocket() {} //@} /// \brief Return the "native" representation of the socket. /// /// In practice, this is the file descriptor of the socket for /// UNIX-like systems so the current implementation simply uses /// \c int as the type of the return value. /// We may have to need revisit this decision later. /// /// In general, the application should avoid using this method; /// it essentially discloses an implementation specific "handle" that /// can change the internal state of the socket (consider the /// application closes it, for example). /// But we sometimes need to perform very low-level operations that /// requires the native representation. Passing the file descriptor /// to a different process is one example. /// This method is provided as a necessary evil for such limited purposes. /// /// This method never throws an exception. /// /// \return The native representation of the socket. This is the socket /// file descriptor for UNIX-like systems. virtual int getNative() const = 0; /// \brief Return the transport protocol of the socket. /// /// Currently, it returns \c IPPROTO_UDP for UDP sockets, and /// \c IPPROTO_TCP for TCP sockets. /// /// This method never throws an exception. /// /// \return IPPROTO_UDP for UDP sockets /// \return IPPROTO_TCP for TCP sockets virtual int getProtocol() const = 0; /// \brief Return a non-usable "dummy" UDP socket for testing. /// /// This is a class method that returns a "mock" of UDP socket. /// This is not associated with any actual socket, and its only /// responsibility is to return \c IPPROTO_UDP from \c getProtocol(). /// The only feasible usage of this socket is for testing so that /// the test code can prepare some "UDP data" even without opening any /// actual socket. /// /// This method never throws an exception. /// /// \return A reference to an \c IOSocket object whose \c getProtocol() /// returns \c IPPROTO_UDP. static IOSocket& getDummyUDPSocket(); /// \brief Return a non-usable "dummy" TCP socket for testing. /// /// See \c getDummyUDPSocket(). This method is its TCP version. /// /// \return A reference to an \c IOSocket object whose \c getProtocol() /// returns \c IPPROTO_TCP. static IOSocket& getDummyTCPSocket(); }; } // namespace asiolink } // namespace isc #endif // IO_SOCKET_H kea-1.1.0/src/lib/asiolink/io_asio_socket.h0000664000175000017500000003600712772017075015523 00000000000000// Copyright (C) 2010-2015 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 IO_ASIO_SOCKET_H #define IO_ASIO_SOCKET_H 1 // IMPORTANT NOTE: only very few ASIO headers files can be included in // this file. In particular, asio.hpp should never be included here. // See the description of the namespace below. #include // for some network system calls #include #include #include #include #include #include #include namespace isc { namespace asiolink { /// \brief Socket not open /// /// Thrown on an attempt to do read/write to a socket that is not open. class SocketNotOpen : public IOError { public: SocketNotOpen(const char* file, size_t line, const char* what) : IOError(file, line, what) {} }; /// \brief Error setting socket options /// /// Thrown if attempt to change socket options fails. class SocketSetError : public IOError { public: SocketSetError(const char* file, size_t line, const char* what) : IOError(file, line, what) {} }; /// \brief Buffer overflow /// /// Thrown if an attempt is made to receive into an area beyond the end of /// the receive data buffer. class BufferOverflow : public IOError { public: BufferOverflow(const char* file, size_t line, const char* what) : IOError(file, line, what) {} }; /// Forward declaration of an IOEndpoint class IOEndpoint; /// \brief I/O Socket with asynchronous operations /// /// This class is a wrapper for the ASIO socket classes such as /// \c ip::tcp::socket and \c ip::udp::socket. /// /// This is the basic IOSocket with additional operations - open, send, receive /// and close. Depending on how the asiolink code develops, it may be a /// temporary class: its main use is to add the template parameter needed for /// the derived classes UDPSocket and TCPSocket but without changing the /// signature of the more basic IOSocket class. /// /// We may revisit this decision when we generalize the wrapper and more /// modules use it. Also, at that point we may define a separate (visible) /// derived class for testing purposes rather than providing factory methods /// (i.e., getDummy variants below). /// /// \param C Template parameter identifying type of the callback object. template class IOAsioSocket : public IOSocket { /// /// \name Constructors and Destructor /// /// Note: The copy constructor and the assignment operator are /// intentionally defined as private, making this class non-copyable. //@{ private: IOAsioSocket(const IOAsioSocket& source); IOAsioSocket& operator=(const IOAsioSocket& source); protected: /// \brief The default constructor. /// /// This is intentionally defined as \c protected as this base class /// should never be instantiated (except as part of a derived class). IOAsioSocket() {} public: /// The destructor. virtual ~IOAsioSocket() {} //@} /// \brief Return the "native" representation of the socket. /// /// In practice, this is the file descriptor of the socket for UNIX-like /// systems so the current implementation simply uses \c int as the type of /// the return value. We may have to need revisit this decision later. /// /// In general, the application should avoid using this method; it /// essentially discloses an implementation specific "handle" that can /// change the internal state of the socket (consider what would happen if /// the application closes it, for example). But we sometimes need to /// perform very low-level operations that requires the native /// representation. Passing the file descriptor to a different process is /// one example. This method is provided as a necessary evil for such /// limited purposes. /// /// This method never throws an exception. /// /// \return The native representation of the socket. This is the socket /// file descriptor for UNIX-like systems. virtual int getNative() const = 0; /// \brief Return the transport protocol of the socket. /// /// Currently, it returns \c IPPROTO_UDP for UDP sockets, and /// \c IPPROTO_TCP for TCP sockets. /// /// This method never throws an exception. /// /// \return \c IPPROTO_UDP for UDP sockets, \c IPPROTO_TCP for TCP sockets virtual int getProtocol() const = 0; /// \brief Is Open() synchronous? /// /// On a TCP socket, an "open" operation is a call to the socket's "open()" /// method followed by a connection to the remote system: it is an /// asynchronous operation. On a UDP socket, it is just a call to "open()" /// and completes synchronously. /// /// For TCP, signalling of the completion of the operation is done by /// by calling the callback function in the normal way. This could be done /// for UDP (by posting en event on the event queue); however, that will /// incur additional overhead in the most common case. So we give the /// caller the choice for calling this open() method synchronously or /// asynchronously. /// /// Owing to the way that the stackless coroutines are implemented, we need /// to know _before_ executing the "open" function whether or not it is /// asynchronous. So this method is called to provide that information. /// /// (The reason there is a need to know is because the call to open() passes /// in the state of the coroutine at the time the call is made. On an /// asynchronous I/O, we need to set the state to point to the statement /// after the call to open() _before_ we pass the coroutine to the open() /// call. Unfortunately, the macros that set the state of the coroutine /// also yield control - which we don't want to do if the open is /// synchronous. Hence we need to know before we make the call to open() /// whether that call will complete asynchronously.) virtual bool isOpenSynchronous() const = 0; /// \brief Open AsioSocket /// /// Opens the socket for asynchronous I/O. The open will complete /// synchronously on UCP or asynchronously on TCP (in which case a callback /// will be queued). /// /// \param endpoint Pointer to the endpoint object. This is ignored for /// a UDP socket (the target is specified in the send call), but /// should be of type TCPEndpoint for a TCP connection. /// \param callback I/O Completion callback, called when the operation has /// completed, but only if the operation was asynchronous. (It is /// ignored on a UDP socket.) virtual void open(const IOEndpoint* endpoint, C& callback) = 0; /// \brief Send Asynchronously /// /// This corresponds to async_send_to() for UDP sockets and async_send() /// for TCP. In both cases an endpoint argument is supplied indicating the /// target of the send - this is ignored for TCP. /// /// \param data Data to send /// \param length Length of data to send /// \param endpoint Target of the send /// \param callback Callback object. virtual void asyncSend(const void* data, size_t length, const IOEndpoint* endpoint, C& callback) = 0; /// \brief Receive Asynchronously /// /// This corresponds to async_receive_from() for UDP sockets and /// async_receive() for TCP. In both cases, an endpoint argument is /// supplied to receive the source of the communication. For TCP it will /// be filled in with details of the connection. /// /// \param data Buffer to receive incoming message /// \param length Length of the data buffer /// \param offset Offset into buffer where data is to be put. Although the /// offset could be implied by adjusting "data" and "length" /// appropriately, using this argument allows data to be specified as /// "const void*" - the overhead of converting it to a pointer to a /// set of bytes is hidden away here. /// \param endpoint Source of the communication /// \param callback Callback object virtual void asyncReceive(void* data, size_t length, size_t offset, IOEndpoint* endpoint, C& callback) = 0; /// \brief Processes received data /// /// In the IOFetch code, data is received into a staging buffer before being /// copied into the target buffer. (This is because (a) we don't know how /// much data we will be receiving, so don't know how to size the output /// buffer and (b) TCP data is preceded by a two-byte count field that needs /// to be discarded before being returned to the user.) /// /// An additional consideration is that TCP data is not received in one /// I/O - it may take a number of I/Os - each receiving any non-zero number /// of bytes - to read the entire message. /// /// So the IOFetch code has to loop until it determines that all the data /// has been read. This is where this method comes in. It has several /// functions: /// /// - It checks if the received data is complete. /// - If data is not complete, decides if the next set of data is to go into /// the start of the staging buffer or at some offset into it. (This /// simplifies the case we could have in a TCP receive where the two-byte /// count field is received in one-byte chunks: we put off interpreting /// the count until we have all of it. The alternative - copying the /// data to the output buffer and interpreting the count from there - /// would require moving the data in the output buffer by two bytes before /// returning it to the caller.) /// - Copies data from the staging buffer into the output buffer. /// /// This functionality mainly applies to TCP receives. For UDP, all the /// data is received in one I/O, so this just copies the data into the /// output buffer. /// /// \param staging Pointer to the start of the staging buffer. /// \param length Amount of data in the staging buffer. /// \param cumulative Amount of data received before the staging buffer is /// processed (this includes the TCP count field if appropriate). /// The value should be set to zero before the receive loop is /// entered, and it will be updated by this method as required. /// \param offset Offset into the staging buffer where the next read should /// put the received data. It should be set to zero before the first /// call and may be updated by this method. /// \param expected Expected amount of data to be received. This is /// really the TCP count field and is set to that value when enough /// of a TCP message is received. It should be initialized to -1 /// before the first read is executed. /// \param outbuff Output buffer. Data in the staging buffer may be copied /// to this output buffer in the call. /// /// \return true if the receive is complete, false if another receive is /// needed. This is always true for UDP, but for TCP involves /// checking the amount of data received so far against the amount /// expected (as indicated by the two-byte count field). If this /// method returns false, another read should be queued and data /// should be read into the staging buffer at offset given by the /// "offset" parameter. virtual bool processReceivedData(const void* staging, size_t length, size_t& cumulative, size_t& offset, size_t& expected, isc::util::OutputBufferPtr& outbuff) = 0; /// \brief Cancel I/O On AsioSocket virtual void cancel() = 0; /// \brief Close socket virtual void close() = 0; }; /// \brief The \c DummyAsioSocket class is a concrete derived class of /// \c IOAsioSocket that is not associated with any real socket. /// /// This main purpose of this class is tests, where it may be desirable to /// instantiate an \c IOAsioSocket object without involving system resource /// allocation such as real network sockets. /// /// \param C Template parameter identifying type of the callback object. template class DummyAsioSocket : public IOAsioSocket { private: DummyAsioSocket(const DummyAsioSocket& source); DummyAsioSocket& operator=(const DummyAsioSocket& source); public: /// \brief Constructor from the protocol number. /// /// The protocol must validly identify a standard network protocol. /// For example, to specify TCP \c protocol must be \c IPPROTO_TCP. /// /// \param protocol The network protocol number for the socket. DummyAsioSocket(const int protocol) : protocol_(protocol) {} /// \brief A dummy derived method of \c IOAsioSocket::getNative(). /// /// \return Always returns -1 as the object is not associated with a real /// (native) socket. virtual int getNative() const { return (-1); } /// \brief A dummy derived method of \c IOAsioSocket::getProtocol(). /// /// \return Protocol socket was created with virtual int getProtocol() const { return (protocol_); } /// \brief Is socket opening synchronous? /// /// \return true - it is for this class. bool isOpenSynchronous() const { return true; } /// \brief Open AsioSocket /// /// A call that is a no-op on UDP sockets, this opens a connection to the /// system identified by the given endpoint. /// The endpoint and callback are unused. /// /// \return false indicating that the operation completed synchronously. virtual bool open(const IOEndpoint*, C&) { return (false); } /// \brief Send Asynchronously /// /// Must be supplied as it is abstract in the base class. /// This is unused. virtual void asyncSend(const void*, size_t, const IOEndpoint*, C&) { } /// \brief Receive Asynchronously /// /// Must be supplied as it is abstract in the base class. /// The parameters are unused. virtual void asyncReceive(void*, size_t, size_t, IOEndpoint*, C&) { } /// \brief Checks if the data received is complete. /// /// The parameters are unused. /// \return Always true virtual bool receiveComplete(const void*, size_t, size_t&, size_t&, size_t&, isc::util::OutputBufferPtr&) { return (true); } /// \brief Cancel I/O On AsioSocket /// /// Must be supplied as it is abstract in the base class. virtual void cancel() { } /// \brief Close socket /// /// Must be supplied as it is abstract in the base class. virtual void close() { } private: const int protocol_; }; } // namespace asiolink } // namespace isc #endif // IO_ASIO_SOCKET_H kea-1.1.0/src/lib/asiolink/io_endpoint.cc0000664000175000017500000000377112772017075015200 00000000000000// Copyright (C) 2011-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 #include #include #include #include #include #include #include #include #include // for some IPC/network system calls #include #include using namespace std; namespace isc { namespace asiolink { const IOEndpoint* IOEndpoint::create(const int protocol, const IOAddress& address, const unsigned short port) { if (protocol == IPPROTO_UDP) { return (new UDPEndpoint(address, port)); } else if (protocol == IPPROTO_TCP) { return (new TCPEndpoint(address, port)); } isc_throw(IOError, "IOEndpoint creation attempt for unsupported protocol: " << protocol); } bool IOEndpoint::operator==(const IOEndpoint& other) const { return (getProtocol() == other.getProtocol() && getPort() == other.getPort() && getFamily() == other.getFamily() && getAddress() == other.getAddress()); } bool IOEndpoint::operator!=(const IOEndpoint& other) const { return (!operator==(other)); } ostream& operator<<(ostream& os, const IOEndpoint& endpoint) { if (endpoint.getFamily() == AF_INET6) { os << "[" << endpoint.getAddress() << "]"; } else { // In practice this should be AF_INET, but it's not guaranteed by // the interface. We'll use the result of textual address // representation opaquely. os << endpoint.getAddress(); } os << ":" << boost::lexical_cast(endpoint.getPort()); return (os); } } // namespace asiolink } // namespace isc kea-1.1.0/src/lib/asiolink/io_error.h0000664000175000017500000000142512772017075014345 00000000000000// Copyright (C) 2011-2015 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 IO_ERROR_H #define IO_ERROR_H #include namespace isc { namespace asiolink { /// \brief An exception that is thrown if an error occurs within the IO /// module. This is mainly intended to be a wrapper exception class for /// ASIO specific exceptions. class IOError : public isc::Exception { public: IOError(const char* file, size_t line, const char* what) : isc::Exception(file, line, what) {} }; } // namespace asiolink } // namespace isc #endif // IO_ERROR_H kea-1.1.0/src/lib/Makefile.am0000664000175000017500000000027212772017075012576 00000000000000# The following build order must be maintained. SUBDIRS = exceptions util log cryptolink dns cc hooks asiolink testutils dhcp config \ stats asiodns dhcp_ddns eval dhcpsrv cfgrpt kea-1.1.0/src/lib/dns/0000775000175000017500000000000012772742660011412 500000000000000kea-1.1.0/src/lib/dns/rrset_collection.h0000664000175000017500000001334212772017075015053 00000000000000// Copyright (C) 2012-2015 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 RRSET_COLLECTION_H #define RRSET_COLLECTION_H 1 #include #include #include #include #include namespace isc { namespace dns { /// \brief libdns++ implementation of RRsetCollectionBase using an STL /// container. class RRsetCollection : public RRsetCollectionBase { public: /// \brief Constructor. /// /// This constructor creates an empty collection without any data in /// it. RRsets can be added to the collection with the \c addRRset() /// method. RRsetCollection() {} /// \brief Constructor. /// /// The \c origin and \c rrclass arguments are required for the zone /// loading, but \c RRsetCollection itself does not do any /// validation, and the collection of RRsets does not have to form a /// valid zone. /// /// \throws MasterLoaderError if there is an error during loading. /// \param filename Name of a file containing a collection of RRs in /// the master file format (which may or may not form a valid zone). /// \param origin The zone origin. /// \param rrclass The zone class. RRsetCollection(const char* filename, const isc::dns::Name& origin, const isc::dns::RRClass& rrclass); /// \brief Constructor. /// /// This constructor is similar to the previous one, but instead of /// taking a filename to load a zone from, it takes an input /// stream. /// /// \throws MasterLoaderError if there is an error during loading. /// \param input_stream The input stream to load from. /// \param origin The zone origin. /// \param rrclass The zone class. RRsetCollection(std::istream& input_stream, const isc::dns::Name& origin, const isc::dns::RRClass& rrclass); /// \brief Destructor virtual ~RRsetCollection() {} /// \brief Add an RRset to the collection. /// /// Does not do any validation whether \c rrset belongs to a /// particular zone or not. A reference to \c rrset is taken in an /// internally managed \c shared_ptr, so even if the caller's /// \c RRsetPtr is destroyed, the RRset it wrapped is still alive /// and managed by the \c RRsetCollection. It throws an /// \c isc::InvalidParameter exception if an rrset with the same /// class, type and name already exists. /// /// Callers must not modify the RRset after adding it to the /// collection, as the rrset is indexed internally by the /// collection. void addRRset(isc::dns::RRsetPtr rrset); /// \brief Remove an RRset from the collection. /// /// RRset(s) matching the \c name, \c rrclass and \c rrtype are /// removed from the collection. /// /// \return \c true if a matching RRset was deleted, \c false if no /// such RRset exists. bool removeRRset(const isc::dns::Name& name, const isc::dns::RRClass& rrclass, const isc::dns::RRType& rrtype); /// \brief Find a matching RRset in the collection. /// /// Returns the RRset in the collection that exactly matches the /// given \c name, \c rrclass and \c rrtype. If no matching RRset /// is found, \c NULL is returned. /// /// \param name The name of the RRset to search for. /// \param rrclass The class of the RRset to search for. /// \param rrtype The type of the RRset to search for. /// \return The RRset if found, \c NULL otherwise. virtual isc::dns::ConstRRsetPtr find(const isc::dns::Name& name, const isc::dns::RRClass& rrclass, const isc::dns::RRType& rrtype) const; /// \brief Find a matching RRset in the collection (non-const /// variant). /// /// See above for a description of the method and arguments. isc::dns::RRsetPtr find(const isc::dns::Name& name, const isc::dns::RRClass& rrclass, const isc::dns::RRType& rrtype); private: template void constructHelper(T source, const isc::dns::Name& origin, const isc::dns::RRClass& rrclass); void loaderCallback(const std::string&, size_t, const std::string&); typedef boost::tuple CollectionKey; typedef std::map CollectionMap; CollectionMap rrsets_; protected: class DnsIter : public RRsetCollectionBase::Iter { public: DnsIter(CollectionMap::iterator& iter) : iter_(iter) {} virtual const isc::dns::AbstractRRset& getValue() { isc::dns::RRsetPtr& rrset = iter_->second; return (*rrset); } virtual IterPtr getNext() { CollectionMap::iterator it = iter_; ++it; return (RRsetCollectionBase::IterPtr(new DnsIter(it))); } virtual bool equals(Iter& other) { const DnsIter* other_real = dynamic_cast(&other); if (other_real == NULL) { return (false); } return (iter_ == other_real->iter_); } private: CollectionMap::iterator iter_; }; virtual RRsetCollectionBase::IterPtr getBeginning(); virtual RRsetCollectionBase::IterPtr getEnd(); }; } // end of namespace dns } // end of namespace isc #endif // RRSET_COLLECTION_H // Local Variables: // mode: c++ // End: kea-1.1.0/src/lib/dns/Makefile.in0000664000175000017500000023373612772742617013417 00000000000000# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = src/lib/dns DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(srcdir)/gen-rdatacode.py.in $(top_srcdir)/depcomp \ $(libdns___include_HEADERS) ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4macros/ax_boost_for_kea.m4 \ $(top_srcdir)/m4macros/ax_isc_rpath.m4 \ $(top_srcdir)/m4macros/libtool.m4 \ $(top_srcdir)/m4macros/ltoptions.m4 \ $(top_srcdir)/m4macros/ltsugar.m4 \ $(top_srcdir)/m4macros/ltversion.m4 \ $(top_srcdir)/m4macros/lt~obsolete.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = gen-rdatacode.py CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(libdir)" \ "$(DESTDIR)$(libdns___includedir)" LTLIBRARIES = $(lib_LTLIBRARIES) am__DEPENDENCIES_1 = libkea_dns___la_DEPENDENCIES = \ $(top_builddir)/src/lib/cryptolink/libkea-cryptolink.la \ $(top_builddir)/src/lib/util/libkea-util.la \ $(top_builddir)/src/lib/exceptions/libkea-exceptions.la \ $(am__DEPENDENCIES_1) am__dirstamp = $(am__leading_dot)dirstamp am_libkea_dns___la_OBJECTS = libkea_dns___la-edns.lo \ libkea_dns___la-exceptions.lo \ libkea_dns___la-master_lexer_inputsource.lo \ libkea_dns___la-labelsequence.lo libkea_dns___la-masterload.lo \ libkea_dns___la-master_lexer.lo \ libkea_dns___la-master_loader.lo libkea_dns___la-message.lo \ libkea_dns___la-messagerenderer.lo libkea_dns___la-name.lo \ libkea_dns___la-nsec3hash.lo libkea_dns___la-opcode.lo \ libkea_dns___la-rcode.lo libkea_dns___la-rdata.lo \ libkea_dns___la-rdatafields.lo libkea_dns___la-rrclass.lo \ libkea_dns___la-rrset.lo libkea_dns___la-rrttl.lo \ libkea_dns___la-rrtype.lo libkea_dns___la-rrcollator.lo \ libkea_dns___la-question.lo libkea_dns___la-serial.lo \ libkea_dns___la-tsig.lo libkea_dns___la-tsigerror.lo \ libkea_dns___la-tsigkey.lo libkea_dns___la-tsigrecord.lo \ libkea_dns___la-master_loader_callbacks.lo \ libkea_dns___la-rrset_collection.lo \ libkea_dns___la-zone_checker.lo \ rdata/generic/detail/libkea_dns___la-char_string.lo \ rdata/generic/detail/libkea_dns___la-nsec_bitmap.lo \ rdata/generic/detail/libkea_dns___la-nsec3param_common.lo \ libkea_dns___la-rdataclass.lo \ libkea_dns___la-rrparamregistry.lo libkea_dns___la_OBJECTS = $(am_libkea_dns___la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = libkea_dns___la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(AM_CXXFLAGS) $(CXXFLAGS) $(libkea_dns___la_LDFLAGS) \ $(LDFLAGS) -o $@ SCRIPTS = $(noinst_SCRIPTS) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CXXFLAGS) $(CXXFLAGS) AM_V_CXX = $(am__v_CXX_@AM_V@) am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@) am__v_CXX_0 = @echo " CXX " $@; am__v_CXX_1 = CXXLD = $(CXX) CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CXXLD = $(am__v_CXXLD_@AM_V@) am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@) am__v_CXXLD_0 = @echo " CXXLD " $@; am__v_CXXLD_1 = COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libkea_dns___la_SOURCES) DIST_SOURCES = $(libkea_dns___la_SOURCES) RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ install-exec-recursive install-html-recursive \ install-info-recursive install-pdf-recursive \ install-ps-recursive install-recursive installcheck-recursive \ installdirs-recursive pdf-recursive ps-recursive \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac HEADERS = $(libdns___include_HEADERS) RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ distdir am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DIST_SUBDIRS = $(SUBDIRS) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ASCIIDOC = @ASCIIDOC@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BOOST_INCLUDES = @BOOST_INCLUDES@ BOOST_LIBS = @BOOST_LIBS@ BOTAN_TOOL = @BOTAN_TOOL@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CQL_CPPFLAGS = @CQL_CPPFLAGS@ CQL_LIBS = @CQL_LIBS@ CRYPTO_CFLAGS = @CRYPTO_CFLAGS@ CRYPTO_INCLUDES = @CRYPTO_INCLUDES@ CRYPTO_LDFLAGS = @CRYPTO_LDFLAGS@ CRYPTO_LIBS = @CRYPTO_LIBS@ CRYPTO_PACKAGE = @CRYPTO_PACKAGE@ CRYPTO_RPATH = @CRYPTO_RPATH@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DBLATEX = @DBLATEX@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DISTCHECK_BOOST_CONFIGURE_FLAG = @DISTCHECK_BOOST_CONFIGURE_FLAG@ DISTCHECK_CRYPTO_CONFIGURE_FLAG = @DISTCHECK_CRYPTO_CONFIGURE_FLAG@ DISTCHECK_GTEST_CONFIGURE_FLAG = @DISTCHECK_GTEST_CONFIGURE_FLAG@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ ELINKS = @ELINKS@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GENHTML = @GENHTML@ GREP = @GREP@ GTEST_CONFIG = @GTEST_CONFIG@ GTEST_INCLUDES = @GTEST_INCLUDES@ GTEST_LDADD = @GTEST_LDADD@ GTEST_LDFLAGS = @GTEST_LDFLAGS@ GTEST_SOURCE = @GTEST_SOURCE@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ KEA_CXXFLAGS = @KEA_CXXFLAGS@ LCOV = @LCOV@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LEXLIB = @LEXLIB@ LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LOG4CPLUS_INCLUDES = @LOG4CPLUS_INCLUDES@ LOG4CPLUS_LIBS = @LOG4CPLUS_LIBS@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ MYSQL_LIBS = @MYSQL_LIBS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PERL = @PERL@ PGSQL_CPPFLAGS = @PGSQL_CPPFLAGS@ PGSQL_LIBS = @PGSQL_LIBS@ PKG_CONFIG = @PKG_CONFIG@ PLANTUML = @PLANTUML@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SEP = @SEP@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ USE_LCOV = @USE_LCOV@ VALGRIND = @VALGRIND@ VERSION = @VERSION@ WARNING_GCC_44_STRICT_ALIASING_CFLAG = @WARNING_GCC_44_STRICT_ALIASING_CFLAG@ XSLTPROC = @XSLTPROC@ YACC = @YACC@ YFLAGS = @YFLAGS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = subdir-objects SUBDIRS = . tests AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib \ $(BOOST_INCLUDES) AM_CXXFLAGS = $(KEA_CXXFLAGS) # These two are created with rrtype/class.h, so not explicitly listed in # BUILT_SOURCES. CLEANFILES = *.gcno *.gcda s-rdatacode python/rrtype_constants_inc.cc \ python/rrclass_constants_inc.cc # TODO: double-check that this is the only way # NOTE: when an rdata file is added, please also add to this list: EXTRA_DIST = rrclass-placeholder.h rrparamregistry-placeholder.cc \ rrtype-placeholder.h rdata/any_255/tsig_250.cc \ rdata/any_255/tsig_250.h rdata/ch_3/a_1.cc rdata/ch_3/a_1.h \ rdata/generic/cname_5.cc rdata/generic/cname_5.h \ rdata/generic/detail/char_string.cc \ rdata/generic/detail/char_string.h \ rdata/generic/detail/lexer_util.h \ rdata/generic/detail/nsec_bitmap.cc \ rdata/generic/detail/nsec_bitmap.h \ rdata/generic/detail/nsec3param_common.cc \ rdata/generic/detail/nsec3param_common.h \ rdata/generic/detail/txt_like.h rdata/generic/detail/ds_like.h \ rdata/generic/dlv_32769.cc rdata/generic/dlv_32769.h \ rdata/generic/dname_39.cc rdata/generic/dname_39.h \ rdata/generic/dnskey_48.cc rdata/generic/dnskey_48.h \ rdata/generic/ds_43.cc rdata/generic/ds_43.h \ rdata/generic/hinfo_13.cc rdata/generic/hinfo_13.h \ rdata/generic/mx_15.cc rdata/generic/mx_15.h \ rdata/generic/naptr_35.cc rdata/generic/naptr_35.h \ rdata/generic/ns_2.cc rdata/generic/ns_2.h \ rdata/generic/nsec3_50.cc rdata/generic/nsec3_50.h \ rdata/generic/nsec3param_51.cc rdata/generic/nsec3param_51.h \ rdata/generic/nsec_47.cc rdata/generic/nsec_47.h \ rdata/generic/opt_41.cc rdata/generic/opt_41.h \ rdata/generic/ptr_12.cc rdata/generic/ptr_12.h \ rdata/generic/rp_17.cc rdata/generic/rp_17.h \ rdata/generic/rrsig_46.cc rdata/generic/rrsig_46.h \ rdata/generic/soa_6.cc rdata/generic/soa_6.h \ rdata/generic/spf_99.cc rdata/generic/spf_99.h \ rdata/generic/sshfp_44.cc rdata/generic/sshfp_44.h \ rdata/generic/tlsa_52.cc rdata/generic/tlsa_52.h \ rdata/generic/txt_16.cc rdata/generic/txt_16.h \ rdata/generic/minfo_14.cc rdata/generic/minfo_14.h \ rdata/generic/afsdb_18.cc rdata/generic/afsdb_18.h \ rdata/generic/caa_257.cc rdata/generic/caa_257.h \ rdata/hs_4/a_1.cc rdata/hs_4/a_1.h rdata/in_1/a_1.cc \ rdata/in_1/a_1.h rdata/in_1/aaaa_28.cc rdata/in_1/aaaa_28.h \ rdata/in_1/dhcid_49.cc rdata/in_1/dhcid_49.h \ rdata/in_1/srv_33.cc rdata/in_1/srv_33.h #EXTRA_DIST += rdata/template.cc #EXTRA_DIST += rdata/template.h noinst_SCRIPTS = gen-rdatacode.py # auto-generate by gen-rdatacode.py: BUILT_SOURCES = rrclass.h rrtype.h rrparamregistry.cc rdataclass.h \ rdataclass.cc lib_LTLIBRARIES = libkea-dns++.la libkea_dns___la_LDFLAGS = -no-undefined -version-info 2:0:1 \ $(AM_LDFLAGS) $(CRYPTO_LDFLAGS) # The following files used to be generated, but they are now part of the git tree: # rrclass.h rrtype.h rrparamregistry.cc rdataclass.h rdataclass.cc libkea_dns___la_SOURCES = dns_fwd.h edns.h edns.cc exceptions.h \ exceptions.cc master_lexer_inputsource.h \ master_lexer_inputsource.cc labelsequence.h labelsequence.cc \ masterload.h masterload.cc master_lexer.h master_lexer.cc \ master_lexer_state.h master_loader.h master_loader.cc \ message.h message.cc messagerenderer.h messagerenderer.cc \ name.h name.cc name_internal.h nsec3hash.h nsec3hash.cc \ opcode.h opcode.cc rcode.h rcode.cc rdata.h rdata.cc \ rdatafields.h rdatafields.cc rrclass.cc rrparamregistry.h \ rrset.h rrset.cc rrttl.h rrttl.cc rrtype.cc rrcollator.h \ rrcollator.cc question.h question.cc serial.h serial.cc tsig.h \ tsig.cc tsigerror.h tsigerror.cc tsigkey.h tsigkey.cc \ tsigrecord.h tsigrecord.cc master_loader_callbacks.h \ master_loader_callbacks.cc master_loader.h \ rrset_collection_base.h rrset_collection.h rrset_collection.cc \ zone_checker.h zone_checker.cc rdata_pimpl_holder.h \ rdata/generic/detail/char_string.h \ rdata/generic/detail/char_string.cc \ rdata/generic/detail/nsec_bitmap.h \ rdata/generic/detail/nsec_bitmap.cc \ rdata/generic/detail/nsec3param_common.cc \ rdata/generic/detail/nsec3param_common.h \ rdata/generic/detail/txt_like.h rdata/generic/detail/ds_like.h \ rdataclass.h rrclass.h rrtype.h rdataclass.cc \ rrparamregistry.cc libkea_dns___la_CPPFLAGS = $(AM_CPPFLAGS) libkea_dns___la_LIBADD = \ $(top_builddir)/src/lib/cryptolink/libkea-cryptolink.la \ $(top_builddir)/src/lib/util/libkea-util.la \ $(top_builddir)/src/lib/exceptions/libkea-exceptions.la \ $(CRYPTO_LIBS) # In ticket #3413 we removed the whole BIND10/Bundy framework. We also want # to not require Python3, hence instead of generating the code every time, # we added the generated files to our repo. It is still possible to regenerate # those files, but that step is no longer required for successful compilation. #rrclass.h rrtype.h rrparamregistry.cc rdataclass.h rdataclass.cc: s-rdatacode libdns___includedir = $(includedir)/$(PACKAGE_NAME)/dns libdns___include_HEADERS = \ edns.h \ exceptions.h \ dns_fwd.h \ labelsequence.h \ message.h \ masterload.h \ master_lexer.h \ master_loader.h \ master_loader_callbacks.h \ messagerenderer.h \ name.h \ question.h \ opcode.h \ rcode.h \ rdata.h \ rrparamregistry.h \ rrset.h \ rrset_collection_base.h \ rrset_collection.h \ rrttl.h \ tsigkey.h \ zone_checker.h all: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) all-recursive .SUFFIXES: .SUFFIXES: .cc .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/lib/dns/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign src/lib/dns/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): gen-rdatacode.py: $(top_builddir)/config.status $(srcdir)/gen-rdatacode.py.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } rdata/generic/detail/$(am__dirstamp): @$(MKDIR_P) rdata/generic/detail @: > rdata/generic/detail/$(am__dirstamp) rdata/generic/detail/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) rdata/generic/detail/$(DEPDIR) @: > rdata/generic/detail/$(DEPDIR)/$(am__dirstamp) rdata/generic/detail/libkea_dns___la-char_string.lo: \ rdata/generic/detail/$(am__dirstamp) \ rdata/generic/detail/$(DEPDIR)/$(am__dirstamp) rdata/generic/detail/libkea_dns___la-nsec_bitmap.lo: \ rdata/generic/detail/$(am__dirstamp) \ rdata/generic/detail/$(DEPDIR)/$(am__dirstamp) rdata/generic/detail/libkea_dns___la-nsec3param_common.lo: \ rdata/generic/detail/$(am__dirstamp) \ rdata/generic/detail/$(DEPDIR)/$(am__dirstamp) libkea-dns++.la: $(libkea_dns___la_OBJECTS) $(libkea_dns___la_DEPENDENCIES) $(EXTRA_libkea_dns___la_DEPENDENCIES) $(AM_V_CXXLD)$(libkea_dns___la_LINK) -rpath $(libdir) $(libkea_dns___la_OBJECTS) $(libkea_dns___la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) -rm -f rdata/generic/detail/*.$(OBJEXT) -rm -f rdata/generic/detail/*.lo distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libkea_dns___la-edns.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libkea_dns___la-exceptions.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libkea_dns___la-labelsequence.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libkea_dns___la-master_lexer.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libkea_dns___la-master_lexer_inputsource.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libkea_dns___la-master_loader.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libkea_dns___la-master_loader_callbacks.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libkea_dns___la-masterload.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libkea_dns___la-message.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libkea_dns___la-messagerenderer.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libkea_dns___la-name.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libkea_dns___la-nsec3hash.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libkea_dns___la-opcode.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libkea_dns___la-question.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libkea_dns___la-rcode.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libkea_dns___la-rdata.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libkea_dns___la-rdataclass.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libkea_dns___la-rdatafields.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libkea_dns___la-rrclass.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libkea_dns___la-rrcollator.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libkea_dns___la-rrparamregistry.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libkea_dns___la-rrset.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libkea_dns___la-rrset_collection.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libkea_dns___la-rrttl.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libkea_dns___la-rrtype.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libkea_dns___la-serial.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libkea_dns___la-tsig.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libkea_dns___la-tsigerror.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libkea_dns___la-tsigkey.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libkea_dns___la-tsigrecord.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libkea_dns___la-zone_checker.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rdata/generic/detail/$(DEPDIR)/libkea_dns___la-char_string.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rdata/generic/detail/$(DEPDIR)/libkea_dns___la-nsec3param_common.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@rdata/generic/detail/$(DEPDIR)/libkea_dns___la-nsec_bitmap.Plo@am__quote@ .cc.o: @am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $< .cc.obj: @am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .cc.lo: @am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ @am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $< libkea_dns___la-edns.lo: edns.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkea_dns___la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libkea_dns___la-edns.lo -MD -MP -MF $(DEPDIR)/libkea_dns___la-edns.Tpo -c -o libkea_dns___la-edns.lo `test -f 'edns.cc' || echo '$(srcdir)/'`edns.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libkea_dns___la-edns.Tpo $(DEPDIR)/libkea_dns___la-edns.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='edns.cc' object='libkea_dns___la-edns.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkea_dns___la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libkea_dns___la-edns.lo `test -f 'edns.cc' || echo '$(srcdir)/'`edns.cc libkea_dns___la-exceptions.lo: exceptions.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkea_dns___la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libkea_dns___la-exceptions.lo -MD -MP -MF $(DEPDIR)/libkea_dns___la-exceptions.Tpo -c -o libkea_dns___la-exceptions.lo `test -f 'exceptions.cc' || echo '$(srcdir)/'`exceptions.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libkea_dns___la-exceptions.Tpo $(DEPDIR)/libkea_dns___la-exceptions.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='exceptions.cc' object='libkea_dns___la-exceptions.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkea_dns___la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libkea_dns___la-exceptions.lo `test -f 'exceptions.cc' || echo '$(srcdir)/'`exceptions.cc libkea_dns___la-master_lexer_inputsource.lo: master_lexer_inputsource.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkea_dns___la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libkea_dns___la-master_lexer_inputsource.lo -MD -MP -MF $(DEPDIR)/libkea_dns___la-master_lexer_inputsource.Tpo -c -o libkea_dns___la-master_lexer_inputsource.lo `test -f 'master_lexer_inputsource.cc' || echo '$(srcdir)/'`master_lexer_inputsource.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libkea_dns___la-master_lexer_inputsource.Tpo $(DEPDIR)/libkea_dns___la-master_lexer_inputsource.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='master_lexer_inputsource.cc' object='libkea_dns___la-master_lexer_inputsource.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkea_dns___la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libkea_dns___la-master_lexer_inputsource.lo `test -f 'master_lexer_inputsource.cc' || echo '$(srcdir)/'`master_lexer_inputsource.cc libkea_dns___la-labelsequence.lo: labelsequence.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkea_dns___la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libkea_dns___la-labelsequence.lo -MD -MP -MF $(DEPDIR)/libkea_dns___la-labelsequence.Tpo -c -o libkea_dns___la-labelsequence.lo `test -f 'labelsequence.cc' || echo '$(srcdir)/'`labelsequence.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libkea_dns___la-labelsequence.Tpo $(DEPDIR)/libkea_dns___la-labelsequence.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='labelsequence.cc' object='libkea_dns___la-labelsequence.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkea_dns___la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libkea_dns___la-labelsequence.lo `test -f 'labelsequence.cc' || echo '$(srcdir)/'`labelsequence.cc libkea_dns___la-masterload.lo: masterload.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkea_dns___la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libkea_dns___la-masterload.lo -MD -MP -MF $(DEPDIR)/libkea_dns___la-masterload.Tpo -c -o libkea_dns___la-masterload.lo `test -f 'masterload.cc' || echo '$(srcdir)/'`masterload.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libkea_dns___la-masterload.Tpo $(DEPDIR)/libkea_dns___la-masterload.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='masterload.cc' object='libkea_dns___la-masterload.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkea_dns___la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libkea_dns___la-masterload.lo `test -f 'masterload.cc' || echo '$(srcdir)/'`masterload.cc libkea_dns___la-master_lexer.lo: master_lexer.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkea_dns___la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libkea_dns___la-master_lexer.lo -MD -MP -MF $(DEPDIR)/libkea_dns___la-master_lexer.Tpo -c -o libkea_dns___la-master_lexer.lo `test -f 'master_lexer.cc' || echo '$(srcdir)/'`master_lexer.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libkea_dns___la-master_lexer.Tpo $(DEPDIR)/libkea_dns___la-master_lexer.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='master_lexer.cc' object='libkea_dns___la-master_lexer.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkea_dns___la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libkea_dns___la-master_lexer.lo `test -f 'master_lexer.cc' || echo '$(srcdir)/'`master_lexer.cc libkea_dns___la-master_loader.lo: master_loader.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkea_dns___la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libkea_dns___la-master_loader.lo -MD -MP -MF $(DEPDIR)/libkea_dns___la-master_loader.Tpo -c -o libkea_dns___la-master_loader.lo `test -f 'master_loader.cc' || echo '$(srcdir)/'`master_loader.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libkea_dns___la-master_loader.Tpo $(DEPDIR)/libkea_dns___la-master_loader.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='master_loader.cc' object='libkea_dns___la-master_loader.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkea_dns___la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libkea_dns___la-master_loader.lo `test -f 'master_loader.cc' || echo '$(srcdir)/'`master_loader.cc libkea_dns___la-message.lo: message.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkea_dns___la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libkea_dns___la-message.lo -MD -MP -MF $(DEPDIR)/libkea_dns___la-message.Tpo -c -o libkea_dns___la-message.lo `test -f 'message.cc' || echo '$(srcdir)/'`message.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libkea_dns___la-message.Tpo $(DEPDIR)/libkea_dns___la-message.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='message.cc' object='libkea_dns___la-message.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkea_dns___la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libkea_dns___la-message.lo `test -f 'message.cc' || echo '$(srcdir)/'`message.cc libkea_dns___la-messagerenderer.lo: messagerenderer.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkea_dns___la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libkea_dns___la-messagerenderer.lo -MD -MP -MF $(DEPDIR)/libkea_dns___la-messagerenderer.Tpo -c -o libkea_dns___la-messagerenderer.lo `test -f 'messagerenderer.cc' || echo '$(srcdir)/'`messagerenderer.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libkea_dns___la-messagerenderer.Tpo $(DEPDIR)/libkea_dns___la-messagerenderer.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='messagerenderer.cc' object='libkea_dns___la-messagerenderer.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkea_dns___la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libkea_dns___la-messagerenderer.lo `test -f 'messagerenderer.cc' || echo '$(srcdir)/'`messagerenderer.cc libkea_dns___la-name.lo: name.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkea_dns___la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libkea_dns___la-name.lo -MD -MP -MF $(DEPDIR)/libkea_dns___la-name.Tpo -c -o libkea_dns___la-name.lo `test -f 'name.cc' || echo '$(srcdir)/'`name.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libkea_dns___la-name.Tpo $(DEPDIR)/libkea_dns___la-name.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='name.cc' object='libkea_dns___la-name.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkea_dns___la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libkea_dns___la-name.lo `test -f 'name.cc' || echo '$(srcdir)/'`name.cc libkea_dns___la-nsec3hash.lo: nsec3hash.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkea_dns___la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libkea_dns___la-nsec3hash.lo -MD -MP -MF $(DEPDIR)/libkea_dns___la-nsec3hash.Tpo -c -o libkea_dns___la-nsec3hash.lo `test -f 'nsec3hash.cc' || echo '$(srcdir)/'`nsec3hash.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libkea_dns___la-nsec3hash.Tpo $(DEPDIR)/libkea_dns___la-nsec3hash.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='nsec3hash.cc' object='libkea_dns___la-nsec3hash.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkea_dns___la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libkea_dns___la-nsec3hash.lo `test -f 'nsec3hash.cc' || echo '$(srcdir)/'`nsec3hash.cc libkea_dns___la-opcode.lo: opcode.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkea_dns___la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libkea_dns___la-opcode.lo -MD -MP -MF $(DEPDIR)/libkea_dns___la-opcode.Tpo -c -o libkea_dns___la-opcode.lo `test -f 'opcode.cc' || echo '$(srcdir)/'`opcode.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libkea_dns___la-opcode.Tpo $(DEPDIR)/libkea_dns___la-opcode.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='opcode.cc' object='libkea_dns___la-opcode.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkea_dns___la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libkea_dns___la-opcode.lo `test -f 'opcode.cc' || echo '$(srcdir)/'`opcode.cc libkea_dns___la-rcode.lo: rcode.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkea_dns___la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libkea_dns___la-rcode.lo -MD -MP -MF $(DEPDIR)/libkea_dns___la-rcode.Tpo -c -o libkea_dns___la-rcode.lo `test -f 'rcode.cc' || echo '$(srcdir)/'`rcode.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libkea_dns___la-rcode.Tpo $(DEPDIR)/libkea_dns___la-rcode.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rcode.cc' object='libkea_dns___la-rcode.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkea_dns___la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libkea_dns___la-rcode.lo `test -f 'rcode.cc' || echo '$(srcdir)/'`rcode.cc libkea_dns___la-rdata.lo: rdata.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkea_dns___la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libkea_dns___la-rdata.lo -MD -MP -MF $(DEPDIR)/libkea_dns___la-rdata.Tpo -c -o libkea_dns___la-rdata.lo `test -f 'rdata.cc' || echo '$(srcdir)/'`rdata.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libkea_dns___la-rdata.Tpo $(DEPDIR)/libkea_dns___la-rdata.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rdata.cc' object='libkea_dns___la-rdata.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkea_dns___la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libkea_dns___la-rdata.lo `test -f 'rdata.cc' || echo '$(srcdir)/'`rdata.cc libkea_dns___la-rdatafields.lo: rdatafields.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkea_dns___la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libkea_dns___la-rdatafields.lo -MD -MP -MF $(DEPDIR)/libkea_dns___la-rdatafields.Tpo -c -o libkea_dns___la-rdatafields.lo `test -f 'rdatafields.cc' || echo '$(srcdir)/'`rdatafields.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libkea_dns___la-rdatafields.Tpo $(DEPDIR)/libkea_dns___la-rdatafields.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rdatafields.cc' object='libkea_dns___la-rdatafields.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkea_dns___la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libkea_dns___la-rdatafields.lo `test -f 'rdatafields.cc' || echo '$(srcdir)/'`rdatafields.cc libkea_dns___la-rrclass.lo: rrclass.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkea_dns___la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libkea_dns___la-rrclass.lo -MD -MP -MF $(DEPDIR)/libkea_dns___la-rrclass.Tpo -c -o libkea_dns___la-rrclass.lo `test -f 'rrclass.cc' || echo '$(srcdir)/'`rrclass.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libkea_dns___la-rrclass.Tpo $(DEPDIR)/libkea_dns___la-rrclass.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rrclass.cc' object='libkea_dns___la-rrclass.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkea_dns___la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libkea_dns___la-rrclass.lo `test -f 'rrclass.cc' || echo '$(srcdir)/'`rrclass.cc libkea_dns___la-rrset.lo: rrset.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkea_dns___la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libkea_dns___la-rrset.lo -MD -MP -MF $(DEPDIR)/libkea_dns___la-rrset.Tpo -c -o libkea_dns___la-rrset.lo `test -f 'rrset.cc' || echo '$(srcdir)/'`rrset.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libkea_dns___la-rrset.Tpo $(DEPDIR)/libkea_dns___la-rrset.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rrset.cc' object='libkea_dns___la-rrset.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkea_dns___la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libkea_dns___la-rrset.lo `test -f 'rrset.cc' || echo '$(srcdir)/'`rrset.cc libkea_dns___la-rrttl.lo: rrttl.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkea_dns___la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libkea_dns___la-rrttl.lo -MD -MP -MF $(DEPDIR)/libkea_dns___la-rrttl.Tpo -c -o libkea_dns___la-rrttl.lo `test -f 'rrttl.cc' || echo '$(srcdir)/'`rrttl.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libkea_dns___la-rrttl.Tpo $(DEPDIR)/libkea_dns___la-rrttl.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rrttl.cc' object='libkea_dns___la-rrttl.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkea_dns___la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libkea_dns___la-rrttl.lo `test -f 'rrttl.cc' || echo '$(srcdir)/'`rrttl.cc libkea_dns___la-rrtype.lo: rrtype.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkea_dns___la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libkea_dns___la-rrtype.lo -MD -MP -MF $(DEPDIR)/libkea_dns___la-rrtype.Tpo -c -o libkea_dns___la-rrtype.lo `test -f 'rrtype.cc' || echo '$(srcdir)/'`rrtype.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libkea_dns___la-rrtype.Tpo $(DEPDIR)/libkea_dns___la-rrtype.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rrtype.cc' object='libkea_dns___la-rrtype.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkea_dns___la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libkea_dns___la-rrtype.lo `test -f 'rrtype.cc' || echo '$(srcdir)/'`rrtype.cc libkea_dns___la-rrcollator.lo: rrcollator.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkea_dns___la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libkea_dns___la-rrcollator.lo -MD -MP -MF $(DEPDIR)/libkea_dns___la-rrcollator.Tpo -c -o libkea_dns___la-rrcollator.lo `test -f 'rrcollator.cc' || echo '$(srcdir)/'`rrcollator.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libkea_dns___la-rrcollator.Tpo $(DEPDIR)/libkea_dns___la-rrcollator.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rrcollator.cc' object='libkea_dns___la-rrcollator.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkea_dns___la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libkea_dns___la-rrcollator.lo `test -f 'rrcollator.cc' || echo '$(srcdir)/'`rrcollator.cc libkea_dns___la-question.lo: question.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkea_dns___la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libkea_dns___la-question.lo -MD -MP -MF $(DEPDIR)/libkea_dns___la-question.Tpo -c -o libkea_dns___la-question.lo `test -f 'question.cc' || echo '$(srcdir)/'`question.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libkea_dns___la-question.Tpo $(DEPDIR)/libkea_dns___la-question.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='question.cc' object='libkea_dns___la-question.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkea_dns___la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libkea_dns___la-question.lo `test -f 'question.cc' || echo '$(srcdir)/'`question.cc libkea_dns___la-serial.lo: serial.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkea_dns___la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libkea_dns___la-serial.lo -MD -MP -MF $(DEPDIR)/libkea_dns___la-serial.Tpo -c -o libkea_dns___la-serial.lo `test -f 'serial.cc' || echo '$(srcdir)/'`serial.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libkea_dns___la-serial.Tpo $(DEPDIR)/libkea_dns___la-serial.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='serial.cc' object='libkea_dns___la-serial.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkea_dns___la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libkea_dns___la-serial.lo `test -f 'serial.cc' || echo '$(srcdir)/'`serial.cc libkea_dns___la-tsig.lo: tsig.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkea_dns___la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libkea_dns___la-tsig.lo -MD -MP -MF $(DEPDIR)/libkea_dns___la-tsig.Tpo -c -o libkea_dns___la-tsig.lo `test -f 'tsig.cc' || echo '$(srcdir)/'`tsig.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libkea_dns___la-tsig.Tpo $(DEPDIR)/libkea_dns___la-tsig.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='tsig.cc' object='libkea_dns___la-tsig.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkea_dns___la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libkea_dns___la-tsig.lo `test -f 'tsig.cc' || echo '$(srcdir)/'`tsig.cc libkea_dns___la-tsigerror.lo: tsigerror.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkea_dns___la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libkea_dns___la-tsigerror.lo -MD -MP -MF $(DEPDIR)/libkea_dns___la-tsigerror.Tpo -c -o libkea_dns___la-tsigerror.lo `test -f 'tsigerror.cc' || echo '$(srcdir)/'`tsigerror.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libkea_dns___la-tsigerror.Tpo $(DEPDIR)/libkea_dns___la-tsigerror.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='tsigerror.cc' object='libkea_dns___la-tsigerror.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkea_dns___la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libkea_dns___la-tsigerror.lo `test -f 'tsigerror.cc' || echo '$(srcdir)/'`tsigerror.cc libkea_dns___la-tsigkey.lo: tsigkey.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkea_dns___la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libkea_dns___la-tsigkey.lo -MD -MP -MF $(DEPDIR)/libkea_dns___la-tsigkey.Tpo -c -o libkea_dns___la-tsigkey.lo `test -f 'tsigkey.cc' || echo '$(srcdir)/'`tsigkey.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libkea_dns___la-tsigkey.Tpo $(DEPDIR)/libkea_dns___la-tsigkey.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='tsigkey.cc' object='libkea_dns___la-tsigkey.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkea_dns___la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libkea_dns___la-tsigkey.lo `test -f 'tsigkey.cc' || echo '$(srcdir)/'`tsigkey.cc libkea_dns___la-tsigrecord.lo: tsigrecord.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkea_dns___la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libkea_dns___la-tsigrecord.lo -MD -MP -MF $(DEPDIR)/libkea_dns___la-tsigrecord.Tpo -c -o libkea_dns___la-tsigrecord.lo `test -f 'tsigrecord.cc' || echo '$(srcdir)/'`tsigrecord.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libkea_dns___la-tsigrecord.Tpo $(DEPDIR)/libkea_dns___la-tsigrecord.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='tsigrecord.cc' object='libkea_dns___la-tsigrecord.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkea_dns___la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libkea_dns___la-tsigrecord.lo `test -f 'tsigrecord.cc' || echo '$(srcdir)/'`tsigrecord.cc libkea_dns___la-master_loader_callbacks.lo: master_loader_callbacks.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkea_dns___la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libkea_dns___la-master_loader_callbacks.lo -MD -MP -MF $(DEPDIR)/libkea_dns___la-master_loader_callbacks.Tpo -c -o libkea_dns___la-master_loader_callbacks.lo `test -f 'master_loader_callbacks.cc' || echo '$(srcdir)/'`master_loader_callbacks.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libkea_dns___la-master_loader_callbacks.Tpo $(DEPDIR)/libkea_dns___la-master_loader_callbacks.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='master_loader_callbacks.cc' object='libkea_dns___la-master_loader_callbacks.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkea_dns___la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libkea_dns___la-master_loader_callbacks.lo `test -f 'master_loader_callbacks.cc' || echo '$(srcdir)/'`master_loader_callbacks.cc libkea_dns___la-rrset_collection.lo: rrset_collection.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkea_dns___la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libkea_dns___la-rrset_collection.lo -MD -MP -MF $(DEPDIR)/libkea_dns___la-rrset_collection.Tpo -c -o libkea_dns___la-rrset_collection.lo `test -f 'rrset_collection.cc' || echo '$(srcdir)/'`rrset_collection.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libkea_dns___la-rrset_collection.Tpo $(DEPDIR)/libkea_dns___la-rrset_collection.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rrset_collection.cc' object='libkea_dns___la-rrset_collection.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkea_dns___la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libkea_dns___la-rrset_collection.lo `test -f 'rrset_collection.cc' || echo '$(srcdir)/'`rrset_collection.cc libkea_dns___la-zone_checker.lo: zone_checker.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkea_dns___la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libkea_dns___la-zone_checker.lo -MD -MP -MF $(DEPDIR)/libkea_dns___la-zone_checker.Tpo -c -o libkea_dns___la-zone_checker.lo `test -f 'zone_checker.cc' || echo '$(srcdir)/'`zone_checker.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libkea_dns___la-zone_checker.Tpo $(DEPDIR)/libkea_dns___la-zone_checker.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='zone_checker.cc' object='libkea_dns___la-zone_checker.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkea_dns___la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libkea_dns___la-zone_checker.lo `test -f 'zone_checker.cc' || echo '$(srcdir)/'`zone_checker.cc rdata/generic/detail/libkea_dns___la-char_string.lo: rdata/generic/detail/char_string.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkea_dns___la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT rdata/generic/detail/libkea_dns___la-char_string.lo -MD -MP -MF rdata/generic/detail/$(DEPDIR)/libkea_dns___la-char_string.Tpo -c -o rdata/generic/detail/libkea_dns___la-char_string.lo `test -f 'rdata/generic/detail/char_string.cc' || echo '$(srcdir)/'`rdata/generic/detail/char_string.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rdata/generic/detail/$(DEPDIR)/libkea_dns___la-char_string.Tpo rdata/generic/detail/$(DEPDIR)/libkea_dns___la-char_string.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rdata/generic/detail/char_string.cc' object='rdata/generic/detail/libkea_dns___la-char_string.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkea_dns___la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o rdata/generic/detail/libkea_dns___la-char_string.lo `test -f 'rdata/generic/detail/char_string.cc' || echo '$(srcdir)/'`rdata/generic/detail/char_string.cc rdata/generic/detail/libkea_dns___la-nsec_bitmap.lo: rdata/generic/detail/nsec_bitmap.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkea_dns___la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT rdata/generic/detail/libkea_dns___la-nsec_bitmap.lo -MD -MP -MF rdata/generic/detail/$(DEPDIR)/libkea_dns___la-nsec_bitmap.Tpo -c -o rdata/generic/detail/libkea_dns___la-nsec_bitmap.lo `test -f 'rdata/generic/detail/nsec_bitmap.cc' || echo '$(srcdir)/'`rdata/generic/detail/nsec_bitmap.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rdata/generic/detail/$(DEPDIR)/libkea_dns___la-nsec_bitmap.Tpo rdata/generic/detail/$(DEPDIR)/libkea_dns___la-nsec_bitmap.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rdata/generic/detail/nsec_bitmap.cc' object='rdata/generic/detail/libkea_dns___la-nsec_bitmap.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkea_dns___la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o rdata/generic/detail/libkea_dns___la-nsec_bitmap.lo `test -f 'rdata/generic/detail/nsec_bitmap.cc' || echo '$(srcdir)/'`rdata/generic/detail/nsec_bitmap.cc rdata/generic/detail/libkea_dns___la-nsec3param_common.lo: rdata/generic/detail/nsec3param_common.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkea_dns___la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT rdata/generic/detail/libkea_dns___la-nsec3param_common.lo -MD -MP -MF rdata/generic/detail/$(DEPDIR)/libkea_dns___la-nsec3param_common.Tpo -c -o rdata/generic/detail/libkea_dns___la-nsec3param_common.lo `test -f 'rdata/generic/detail/nsec3param_common.cc' || echo '$(srcdir)/'`rdata/generic/detail/nsec3param_common.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) rdata/generic/detail/$(DEPDIR)/libkea_dns___la-nsec3param_common.Tpo rdata/generic/detail/$(DEPDIR)/libkea_dns___la-nsec3param_common.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rdata/generic/detail/nsec3param_common.cc' object='rdata/generic/detail/libkea_dns___la-nsec3param_common.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkea_dns___la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o rdata/generic/detail/libkea_dns___la-nsec3param_common.lo `test -f 'rdata/generic/detail/nsec3param_common.cc' || echo '$(srcdir)/'`rdata/generic/detail/nsec3param_common.cc libkea_dns___la-rdataclass.lo: rdataclass.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkea_dns___la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libkea_dns___la-rdataclass.lo -MD -MP -MF $(DEPDIR)/libkea_dns___la-rdataclass.Tpo -c -o libkea_dns___la-rdataclass.lo `test -f 'rdataclass.cc' || echo '$(srcdir)/'`rdataclass.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libkea_dns___la-rdataclass.Tpo $(DEPDIR)/libkea_dns___la-rdataclass.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rdataclass.cc' object='libkea_dns___la-rdataclass.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkea_dns___la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libkea_dns___la-rdataclass.lo `test -f 'rdataclass.cc' || echo '$(srcdir)/'`rdataclass.cc libkea_dns___la-rrparamregistry.lo: rrparamregistry.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkea_dns___la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libkea_dns___la-rrparamregistry.lo -MD -MP -MF $(DEPDIR)/libkea_dns___la-rrparamregistry.Tpo -c -o libkea_dns___la-rrparamregistry.lo `test -f 'rrparamregistry.cc' || echo '$(srcdir)/'`rrparamregistry.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libkea_dns___la-rrparamregistry.Tpo $(DEPDIR)/libkea_dns___la-rrparamregistry.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rrparamregistry.cc' object='libkea_dns___la-rrparamregistry.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkea_dns___la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libkea_dns___la-rrparamregistry.lo `test -f 'rrparamregistry.cc' || echo '$(srcdir)/'`rrparamregistry.cc mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs -rm -rf rdata/generic/detail/.libs rdata/generic/detail/_libs install-libdns___includeHEADERS: $(libdns___include_HEADERS) @$(NORMAL_INSTALL) @list='$(libdns___include_HEADERS)'; test -n "$(libdns___includedir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(libdns___includedir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libdns___includedir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(libdns___includedir)'"; \ $(INSTALL_HEADER) $$files "$(DESTDIR)$(libdns___includedir)" || exit $$?; \ done uninstall-libdns___includeHEADERS: @$(NORMAL_UNINSTALL) @list='$(libdns___include_HEADERS)'; test -n "$(libdns___includedir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(libdns___includedir)'; $(am__uninstall_files_from_dir) # This directory's subdirectories are mostly independent; you can cd # into them and run 'make' without going through this Makefile. # To change the values of 'make' variables: instead of editing Makefiles, # (1) if the variable is set in 'config.status', edit 'config.status' # (which will cause the Makefiles to be regenerated when you run 'make'); # (2) otherwise, pass the desired values on the 'make' command line. $(am__recursive_targets): @fail=; \ if $(am__make_keepgoing); then \ failcom='fail=yes'; \ else \ failcom='exit 1'; \ fi; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-recursive CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-recursive cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done check-am: all-am check: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) check-recursive all-am: Makefile $(LTLIBRARIES) $(SCRIPTS) $(HEADERS) installdirs: installdirs-recursive installdirs-am: for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(libdns___includedir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) -rm -f rdata/generic/detail/$(DEPDIR)/$(am__dirstamp) -rm -f rdata/generic/detail/$(am__dirstamp) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) clean: clean-recursive clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ mostlyclean-am distclean: distclean-recursive -rm -rf ./$(DEPDIR) rdata/generic/detail/$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-libdns___includeHEADERS install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-libLTLIBRARIES install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -rf ./$(DEPDIR) rdata/generic/detail/$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: uninstall-libLTLIBRARIES \ uninstall-libdns___includeHEADERS .MAKE: $(am__recursive_targets) all check install install-am \ install-strip .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ check-am clean clean-generic clean-libLTLIBRARIES \ clean-libtool cscopelist-am ctags ctags-am distclean \ distclean-compile distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am \ install-libLTLIBRARIES install-libdns___includeHEADERS \ install-man install-pdf install-pdf-am install-ps \ install-ps-am install-strip installcheck installcheck-am \ installdirs installdirs-am maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am uninstall-libLTLIBRARIES \ uninstall-libdns___includeHEADERS rrclass.h: rrclass-placeholder.h rrtype.h: rrtype-placeholder.h rrparamregistry.cc: rrparamregistry-placeholder.cc s-rdatacode: Makefile $(EXTRA_DIST) $(PYTHON) ./gen-rdatacode.py touch $@ # Purposely not installing these headers: # name_internal.h: used only internally, and not actually DNS specific # rdata/*/detail/*.h: these are internal use only # rrclass-placeholder.h # rrtype-placeholder.h # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: kea-1.1.0/src/lib/dns/tsigrecord.cc0000664000175000017500000000750512772017075014010 00000000000000// Copyright (C) 2011-2015 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 #include #include #include #include #include #include #include using namespace isc::util; using namespace isc::dns::rdata; namespace { // Internally used constants: // Size in octets for the RR type, class TTL, RDLEN fields. const size_t RR_COMMON_LEN = 10; // Size in octets for the fixed part of TSIG RDATAs. // - Time Signed (6) // - Fudge (2) // - MAC Size (2) // - Original ID (2) // - Error (2) // - Other Len (2) const size_t RDATA_COMMON_LEN = 16; } namespace isc { namespace dns { TSIGRecord::TSIGRecord(const Name& key_name, const rdata::any::TSIG& tsig_rdata) : key_name_(key_name), rdata_(tsig_rdata), length_(RR_COMMON_LEN + RDATA_COMMON_LEN + key_name_.getLength() + rdata_.getAlgorithm().getLength() + rdata_.getMACSize() + rdata_.getOtherLen()) {} namespace { // This is a straightforward wrapper of dynamic_cast. // We use this so that we can throw the DNSMessageFORMERR exception when // unexpected type of RDATA is detected in the member initialization list // of the constructor below. const any::TSIG& castToTSIGRdata(const rdata::Rdata& rdata) { const any::TSIG* tsig_rdata = dynamic_cast(&rdata); if (!tsig_rdata) { isc_throw(DNSMessageFORMERR, "TSIG record is being constructed from " "incompatible RDATA: " << rdata.toText()); } return (*tsig_rdata); } } TSIGRecord::TSIGRecord(const Name& name, const RRClass& rrclass, const RRTTL& ttl, const rdata::Rdata& rdata, size_t length) : key_name_(name), rdata_(castToTSIGRdata(rdata)), length_(length) { if (rrclass != getClass()) { isc_throw(DNSMessageFORMERR, "Unexpected TSIG RR class: " << rrclass); } if (ttl != RRTTL(TSIG_TTL)) { isc_throw(DNSMessageFORMERR, "Unexpected TSIG TTL: " << ttl); } } const RRClass& TSIGRecord::getClass() { return (RRClass::ANY()); } const RRTTL& TSIGRecord::getTTL() { static RRTTL ttl(TSIG_TTL); return (ttl); } namespace { template void toWireCommon(OUTPUT& output, const rdata::any::TSIG& rdata) { // RR type, class, TTL are fixed constants. RRType::TSIG().toWire(output); TSIGRecord::getClass().toWire(output); output.writeUint32(TSIGRecord::TSIG_TTL); // RDLEN output.writeUint16(RDATA_COMMON_LEN + rdata.getAlgorithm().getLength() + rdata.getMACSize() + rdata.getOtherLen()); // TSIG RDATA rdata.toWire(output); } } int TSIGRecord::toWire(AbstractMessageRenderer& renderer) const { // If adding the TSIG would exceed the size limit, don't do it. if (renderer.getLength() + length_ > renderer.getLengthLimit()) { renderer.setTruncated(); return (0); } // key name = owner. note that we disable compression. renderer.writeName(key_name_, false); toWireCommon(renderer, rdata_); return (1); } int TSIGRecord::toWire(OutputBuffer& buffer) const { key_name_.toWire(buffer); toWireCommon(buffer, rdata_); return (1); } std::string TSIGRecord::toText() const { return (key_name_.toText() + " " + RRTTL(TSIG_TTL).toText() + " " + getClass().toText() + " " + RRType::TSIG().toText() + " " + rdata_.toText() + "\n"); } std::ostream& operator<<(std::ostream& os, const TSIGRecord& record) { return (os << record.toText()); } } // namespace dns } // namespace isc kea-1.1.0/src/lib/dns/rdata.cc0000664000175000017500000002710512772017075012734 00000000000000// Copyright (C) 2010-2015 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; using boost::lexical_cast; using namespace isc::util; namespace isc { namespace dns { namespace rdata { uint16_t Rdata::getLength() const { OutputBuffer obuffer(0); toWire(obuffer); return (obuffer.getLength()); } // XXX: we need to specify std:: for string to help doxygen match the // function signature with that given in the header file. RdataPtr createRdata(const RRType& rrtype, const RRClass& rrclass, const std::string& rdata_string) { return (RRParamRegistry::getRegistry().createRdata(rrtype, rrclass, rdata_string)); } RdataPtr createRdata(const RRType& rrtype, const RRClass& rrclass, isc::util::InputBuffer& buffer, size_t len) { if (len > MAX_RDLENGTH) { isc_throw(InvalidRdataLength, "RDLENGTH too large"); } size_t old_pos = buffer.getPosition(); RdataPtr rdata = RRParamRegistry::getRegistry().createRdata(rrtype, rrclass, buffer, len); if (buffer.getPosition() - old_pos != len) { isc_throw(InvalidRdataLength, "RDLENGTH mismatch: " << buffer.getPosition() - old_pos << " != " << len); } return (rdata); } RdataPtr createRdata(const RRType& rrtype, const RRClass& rrclass, const Rdata& source) { return (RRParamRegistry::getRegistry().createRdata(rrtype, rrclass, source)); } namespace { void fromtextError(bool& error_issued, const MasterLexer& lexer, MasterLoaderCallbacks& callbacks, const MasterToken* token, const char* reason) { // Don't be too noisy if there are many issues for single RDATA if (error_issued) { return; } error_issued = true; if (token == NULL) { callbacks.error(lexer.getSourceName(), lexer.getSourceLine(), "createRdata from text failed: " + string(reason)); return; } switch (token->getType()) { case MasterToken::STRING: case MasterToken::QSTRING: callbacks.error(lexer.getSourceName(), lexer.getSourceLine(), "createRdata from text failed near '" + token->getString() + "': " + string(reason)); break; case MasterToken::ERROR: callbacks.error(lexer.getSourceName(), lexer.getSourceLine(), "createRdata from text failed: " + token->getErrorText()); break; default: // This case shouldn't happen based on how we use MasterLexer in // createRdata(), so we could assert() that here. But since it // depends on detailed behavior of other classes, we treat the case // in a bit less harsh way. isc_throw(Unexpected, "bug: createRdata() saw unexpected token type"); } } } RdataPtr createRdata(const RRType& rrtype, const RRClass& rrclass, MasterLexer& lexer, const Name* origin, MasterLoader::Options options, MasterLoaderCallbacks& callbacks) { RdataPtr rdata; bool error_issued = false; try { rdata = RRParamRegistry::getRegistry().createRdata( rrtype, rrclass, lexer, origin, options, callbacks); } catch (const MasterLexer::LexerError& error) { fromtextError(error_issued, lexer, callbacks, &error.token_, ""); } catch (const Exception& ex) { // Catching all isc::Exception is too broad, but right now we don't // have better granularity. When we complete #2518 we can make this // finer. fromtextError(error_issued, lexer, callbacks, NULL, ex.what()); } // Other exceptions mean a serious implementation bug or fatal system // error; it doesn't make sense to catch and try to recover from them // here. Just propagate. // Consume to end of line / file. // Call callback via fromtextError once if there was an error. do { const MasterToken& token = lexer.getNextToken(); switch (token.getType()) { case MasterToken::END_OF_LINE: return (rdata); case MasterToken::END_OF_FILE: callbacks.warning(lexer.getSourceName(), lexer.getSourceLine(), "file does not end with newline"); return (rdata); default: rdata.reset(); // we'll return NULL fromtextError(error_issued, lexer, callbacks, &token, "extra input text"); // Continue until we see EOL or EOF } } while (true); // We shouldn't reach here assert(false); return (RdataPtr()); // add explicit return to silence some compilers } int compareNames(const Name& n1, const Name& n2) { size_t len1 = n1.getLength(); size_t len2 = n2.getLength(); size_t cmplen = min(len1, len2); for (size_t i = 0; i < cmplen; ++i) { uint8_t c1 = tolower(n1.at(i)); uint8_t c2 = tolower(n2.at(i)); if (c1 < c2) { return (-1); } else if (c1 > c2) { return (1); } } return ((len1 == len2) ? 0 : (len1 < len2) ? -1 : 1); } namespace generic { struct GenericImpl { GenericImpl(const vector& data) : data_(data) {} vector data_; }; Generic::Generic(isc::util::InputBuffer& buffer, size_t rdata_len) { if (rdata_len > MAX_RDLENGTH) { isc_throw(InvalidRdataLength, "RDLENGTH too large"); } vector data(rdata_len); if (rdata_len > 0) { buffer.readData(&data[0], rdata_len); } impl_ = new GenericImpl(data); } GenericImpl* Generic::constructFromLexer(MasterLexer& lexer) { const MasterToken& token = lexer.getNextToken(MasterToken::STRING); if (token.getString() != "\\#") { isc_throw(InvalidRdataText, "Missing the special token (\\#) for " "unknown RDATA encoding"); } // Initialize with an absurd value. uint32_t rdlen = 65536; try { rdlen = lexer.getNextToken(MasterToken::NUMBER).getNumber(); } catch (const MasterLexer::LexerError&) { isc_throw(InvalidRdataLength, "Unknown RDATA length is invalid"); } if (rdlen > 65535) { isc_throw(InvalidRdataLength, "Unknown RDATA length is out of range: " << rdlen); } vector data; if (rdlen > 0) { string hex_txt; string hex_part; // Whitespace is allowed within hex data, so read to the end of input. while (true) { const MasterToken& token = lexer.getNextToken(MasterToken::STRING, true); if ((token.getType() == MasterToken::END_OF_FILE) || (token.getType() == MasterToken::END_OF_LINE)) { // Unget the last read token as createRdata() expects us // to leave it at the end-of-line or end-of-file when we // return. lexer.ungetToken(); break; } token.getString(hex_part); hex_txt.append(hex_part); } try { isc::util::encode::decodeHex(hex_txt, data); } catch (const isc::BadValue& ex) { isc_throw(InvalidRdataText, "Invalid hex encoding of generic RDATA: " << ex.what()); } } if (data.size() != rdlen) { isc_throw(InvalidRdataLength, "Size of unknown RDATA hex data doesn't match RDLENGTH: " << data.size() << " vs. " << rdlen); } return (new GenericImpl(data)); } Generic::Generic(const std::string& rdata_string) : impl_(NULL) { // We use auto_ptr here because if there is an exception in this // constructor, the destructor is not called and there could be a // leak of the GenericImpl that constructFromLexer() returns. std::auto_ptr impl_ptr(NULL); try { std::istringstream ss(rdata_string); MasterLexer lexer; lexer.pushSource(ss); impl_ptr.reset(constructFromLexer(lexer)); if (lexer.getNextToken().getType() != MasterToken::END_OF_FILE) { isc_throw(InvalidRdataText, "extra input text for unknown RDATA: " << rdata_string); } } catch (const MasterLexer::LexerError& ex) { isc_throw(InvalidRdataText, "Failed to construct unknown RDATA " "from '" << rdata_string << "': " << ex.what()); } impl_ = impl_ptr.release(); } Generic::Generic(MasterLexer& lexer, const Name*, MasterLoader::Options, MasterLoaderCallbacks&) : impl_(constructFromLexer(lexer)) { } Generic::~Generic() { delete impl_; } Generic::Generic(const Generic& source) : Rdata(), impl_(new GenericImpl(*source.impl_)) {} Generic& // Our check is better than the usual if (this == &source), // but cppcheck doesn't recognize it. // cppcheck-suppress operatorEqToSelf Generic::operator=(const Generic& source) { if (impl_ == source.impl_) { return (*this); } GenericImpl* newimpl = new GenericImpl(*source.impl_); delete impl_; impl_ = newimpl; return (*this); } namespace { class UnknownRdataDumper { public: UnknownRdataDumper(ostringstream& oss) : oss_(&oss) {} void operator()(const unsigned char d) { *oss_ << setw(2) << static_cast(d); } private: ostringstream* oss_; }; } string Generic::toText() const { ostringstream oss; oss << "\\# " << impl_->data_.size() << " "; oss.fill('0'); oss << right << hex; for_each(impl_->data_.begin(), impl_->data_.end(), UnknownRdataDumper(oss)); return (oss.str()); } void Generic::toWire(isc::util::OutputBuffer& buffer) const { buffer.writeData(&impl_->data_[0], impl_->data_.size()); } void Generic::toWire(AbstractMessageRenderer& renderer) const { renderer.writeData(&impl_->data_[0], impl_->data_.size()); } namespace { inline int compare_internal(const GenericImpl& lhs, const GenericImpl& rhs) { size_t this_len = lhs.data_.size(); size_t other_len = rhs.data_.size(); size_t len = (this_len < other_len) ? this_len : other_len; int cmp; // TODO: is there a need to check len - should we just assert? // (Depends if it is possible for rdata to have zero length) if ((len != 0) && ((cmp = memcmp(&lhs.data_[0], &rhs.data_[0], len)) != 0)) { return (cmp); } else { return ((this_len == other_len) ? 0 : (this_len < other_len) ? -1 : 1); } } } int Generic::compare(const Rdata& other) const { const Generic& other_rdata = dynamic_cast(other); return (compare_internal(*impl_, *other_rdata.impl_)); } std::ostream& operator<<(std::ostream& os, const Generic& rdata) { return (os << rdata.toText()); } } // end of namespace generic } // end of namespace rdata } } kea-1.1.0/src/lib/dns/tsig.cc0000664000175000017500000005542312772017075012613 00000000000000// Copyright (C) 2011-2015 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; using namespace isc::util; using namespace isc::cryptolink; using namespace isc::dns::rdata; namespace isc { namespace dns { namespace { typedef boost::shared_ptr HMACPtr; // TSIG uses 48-bit unsigned integer to represent time signed. // Since gettimeWrapper() returns a 64-bit *signed* integer, we // make sure it's stored in an unsigned 64-bit integer variable and // represents a value in the expected range. (In reality, however, // gettimeWrapper() will return a positive integer that will fit // in 48 bits) uint64_t getTSIGTime() { return (detail::gettimeWrapper() & 0x0000ffffffffffffULL); } } struct TSIGContext::TSIGContextImpl { TSIGContextImpl(const TSIGKey& key, TSIGError error = TSIGError::NOERROR()) : state_(INIT), key_(key), error_(error), previous_timesigned_(0), digest_len_(0), last_sig_dist_(-1) { if (error == TSIGError::NOERROR()) { // In normal (NOERROR) case, the key should be valid, and we // should be able to pre-create a corresponding HMAC object, // which will be likely to be used for sign or verify later. // We do this in the constructor so that we can know the expected // digest length in advance. The creation should normally succeed, // but the key information could be still broken, which could // trigger an exception inside the cryptolink module. We ignore // it at this moment; a subsequent sign/verify operation will try // to create the HMAC, which would also fail. try { hmac_.reset(CryptoLink::getCryptoLink().createHMAC( key_.getSecret(), key_.getSecretLength(), key_.getAlgorithm()), deleteHMAC); } catch (const isc::Exception&) { return; } size_t digestbits = key_.getDigestbits(); size_t default_digest_len = hmac_->getOutputLength(); if (digestbits > 0) { digest_len_ = (digestbits + 7) / 8; // sanity (cf. RFC 4635) if ((digest_len_ < 10) || (digest_len_ < (default_digest_len / 2)) || (digest_len_ > default_digest_len)) { // should emit a warning? digest_len_ = default_digest_len; } } else { digest_len_ = default_digest_len; } } } // This helper method is used from verify(). It's expected to be called // just before verify() returns. It updates internal state based on // the verification result and return the TSIGError to be returned to // the caller of verify(), so that verify() can call this method within // its 'return' statement. TSIGError postVerifyUpdate(TSIGError error, const void* digest, uint16_t digest_len) { if (state_ == INIT) { state_ = RECEIVED_REQUEST; } else if (state_ == SENT_REQUEST && error == TSIGError::NOERROR()) { state_ = VERIFIED_RESPONSE; } if (digest != NULL) { previous_digest_.assign(static_cast(digest), static_cast(digest) + digest_len); } error_ = error; return (error); } // A shortcut method to create an HMAC object for sign/verify. If one // has been successfully created in the constructor, return it; otherwise // create a new one and return it. In the former case, the ownership is // transferred to the caller; the stored HMAC will be reset after the // call. HMACPtr createHMAC() { if (hmac_) { HMACPtr ret = HMACPtr(); ret.swap(hmac_); return (ret); } return (HMACPtr(CryptoLink::getCryptoLink().createHMAC( key_.getSecret(), key_.getSecretLength(), key_.getAlgorithm()), deleteHMAC)); } // The following three are helper methods to compute the digest for // TSIG sign/verify in order to unify the common code logic for sign() // and verify() and to keep these callers concise. // These methods take an HMAC object, which will be updated with the // calculated digest. // Note: All methods construct a local OutputBuffer as a work space with a // fixed initial buffer size to avoid intermediate buffer extension. // This should be efficient enough, especially for fundamentally expensive // operation like cryptographic sign/verify, but if the creation of the // buffer in each helper method is still identified to be a severe // performance bottleneck, we could have this class a buffer as a member // variable and reuse it throughout the object's lifetime. Right now, // we prefer keeping the scope for local things as small as possible. void digestPreviousMAC(HMACPtr hmac); void digestTSIGVariables(HMACPtr hmac, uint16_t rrclass, uint32_t rrttl, uint64_t time_signed, uint16_t fudge, uint16_t error, uint16_t otherlen, const void* otherdata, bool time_variables_only) const; void digestDNSMessage(HMACPtr hmac, uint16_t qid, const void* data, size_t data_len) const; State state_; const TSIGKey key_; vector previous_digest_; TSIGError error_; uint64_t previous_timesigned_; // only meaningful for response with BADTIME size_t digest_len_; HMACPtr hmac_; // This is the distance from the last verified signed message. Value of 0 // means the last message was signed. Special value -1 means there was no // signed message yet. int last_sig_dist_; }; void TSIGContext::TSIGContextImpl::digestPreviousMAC(HMACPtr hmac) { // We should have ensured the digest size fits 16 bits within this class // implementation. assert(previous_digest_.size() <= 0xffff); if (previous_digest_.empty()) { // The previous digest was already used. We're in the middle of // TCP stream somewhere and we already pushed some unsigned message // into the HMAC state. return; } OutputBuffer buffer(sizeof(uint16_t) + previous_digest_.size()); const uint16_t previous_digest_len(previous_digest_.size()); buffer.writeUint16(previous_digest_len); if (previous_digest_len != 0) { buffer.writeData(&previous_digest_[0], previous_digest_len); } hmac->update(buffer.getData(), buffer.getLength()); } void TSIGContext::TSIGContextImpl::digestTSIGVariables( HMACPtr hmac, uint16_t rrclass, uint32_t rrttl, uint64_t time_signed, uint16_t fudge, uint16_t error, uint16_t otherlen, const void* otherdata, bool time_variables_only) const { // It's bit complicated, but we can still predict the necessary size of // the data to be digested. So we precompute it to avoid possible // reallocation inside OutputBuffer (not absolutely necessary, but this // is a bit more efficient) size_t data_size = 8; if (!time_variables_only) { data_size += 10 + key_.getKeyName().getLength() + key_.getAlgorithmName().getLength(); } OutputBuffer buffer(data_size); if (!time_variables_only) { key_.getKeyName().toWire(buffer); buffer.writeUint16(rrclass); buffer.writeUint32(rrttl); key_.getAlgorithmName().toWire(buffer); } buffer.writeUint16(time_signed >> 32); buffer.writeUint32(time_signed & 0xffffffff); buffer.writeUint16(fudge); if (!time_variables_only) { buffer.writeUint16(error); buffer.writeUint16(otherlen); } hmac->update(buffer.getData(), buffer.getLength()); if (!time_variables_only && otherlen > 0) { hmac->update(otherdata, otherlen); } } // In digestDNSMessage, we exploit some minimum knowledge of DNS message // format: // - the header section has a fixed length of 12 octets (MESSAGE_HEADER_LEN) // - the offset in the header section to the ID field is 0 // - the offset in the header section to the ARCOUNT field is 10 (and the field // length is 2 octets) // We could construct a separate Message object from the given data, adjust // fields via the Message interfaces and then render it back to a separate // buffer, but that would be overkilling. The DNS message header has a // fixed length and necessary modifications are quite straightforward, so // we do the job using lower level interfaces. namespace { const size_t MESSAGE_HEADER_LEN = 12; } void TSIGContext::TSIGContextImpl::digestDNSMessage(HMACPtr hmac, uint16_t qid, const void* data, size_t data_len) const { OutputBuffer buffer(MESSAGE_HEADER_LEN); const uint8_t* msgptr = static_cast(data); // Install the original ID buffer.writeUint16(qid); msgptr += sizeof(uint16_t); // Copy the rest of the header except the ARCOUNT field. buffer.writeData(msgptr, 8); msgptr += 8; // Install the adjusted ARCOUNT (we don't care even if the value is bogus // and it underflows; it would simply result in verification failure) buffer.writeUint16(InputBuffer(msgptr, sizeof(uint16_t)).readUint16() - 1); msgptr += 2; // Digest the header and the rest of the DNS message hmac->update(buffer.getData(), buffer.getLength()); hmac->update(msgptr, data_len - MESSAGE_HEADER_LEN); } TSIGContext::TSIGContext(const TSIGKey& key) : impl_(new TSIGContextImpl(key)) { } TSIGContext::TSIGContext(const Name& key_name, const Name& algorithm_name, const TSIGKeyRing& keyring) : impl_(NULL) { const TSIGKeyRing::FindResult result(keyring.find(key_name, algorithm_name)); if (result.code == TSIGKeyRing::NOTFOUND) { // If not key is found, create a dummy key with the specified key // parameters and empty secret. In the common scenario this will // be used in subsequent response with a TSIG indicating a BADKEY // error. impl_ = new TSIGContextImpl(TSIGKey(key_name, algorithm_name, NULL, 0), TSIGError::BAD_KEY()); } else { impl_ = new TSIGContextImpl(*result.key); } } TSIGContext::~TSIGContext() { delete impl_; } size_t TSIGContext::getTSIGLength() const { // // The space required for an TSIG record is: // // n1 bytes for the (key) name // 2 bytes for the type // 2 bytes for the class // 4 bytes for the ttl // 2 bytes for the rdlength // n2 bytes for the algorithm name // 6 bytes for the time signed // 2 bytes for the fudge // 2 bytes for the MAC size // x bytes for the MAC // 2 bytes for the original id // 2 bytes for the error // 2 bytes for the other data length // y bytes for the other data (at most) // --------------------------------- // 26 + n1 + n2 + x + y bytes // // Normally the digest length ("x") is the length of the underlying // hash output. If a key related error occurred, however, the // corresponding TSIG will be "unsigned", and the digest length will be 0. const size_t digest_len = (impl_->error_ == TSIGError::BAD_KEY() || impl_->error_ == TSIGError::BAD_SIG()) ? 0 : impl_->digest_len_; // Other Len ("y") is normally 0; if BAD_TIME error occurred, the // subsequent TSIG will contain 48 bits of the server current time. const size_t other_len = (impl_->error_ == TSIGError::BAD_TIME()) ? 6 : 0; return (26 + impl_->key_.getKeyName().getLength() + impl_->key_.getAlgorithmName().getLength() + digest_len + other_len); } TSIGContext::State TSIGContext::getState() const { return (impl_->state_); } TSIGError TSIGContext::getError() const { return (impl_->error_); } ConstTSIGRecordPtr TSIGContext::sign(const uint16_t qid, const void* const data, const size_t data_len) { if (impl_->state_ == VERIFIED_RESPONSE) { isc_throw(TSIGContextError, "TSIG sign attempt after verifying a response"); } if (data == NULL || data_len == 0) { isc_throw(InvalidParameter, "TSIG sign error: empty data is given"); } TSIGError error(TSIGError::NOERROR()); const uint64_t now = getTSIGTime(); // For responses adjust the error code. if (impl_->state_ == RECEIVED_REQUEST) { error = impl_->error_; } // For errors related to key or MAC, return an unsigned response as // specified in Section 4.3 of RFC2845. if (error == TSIGError::BAD_SIG() || error == TSIGError::BAD_KEY()) { ConstTSIGRecordPtr tsig(new TSIGRecord( impl_->key_.getKeyName(), any::TSIG(impl_->key_.getAlgorithmName(), now, DEFAULT_FUDGE, 0, NULL, qid, error.getCode(), 0, NULL))); impl_->previous_digest_.clear(); impl_->state_ = SENT_RESPONSE; return (tsig); } HMACPtr hmac(impl_->createHMAC()); // If the context has previous MAC (either the Request MAC or its own // previous MAC), digest it. if (impl_->state_ != INIT) { impl_->digestPreviousMAC(hmac); } // Digest the message (without TSIG) hmac->update(data, data_len); // Digest TSIG variables. // First, prepare some non constant variables. const uint64_t time_signed = (error == TSIGError::BAD_TIME()) ? impl_->previous_timesigned_ : now; // For BADTIME error, we include 6 bytes of other data. // (6 bytes = size of time signed value) const uint16_t otherlen = (error == TSIGError::BAD_TIME()) ? 6 : 0; OutputBuffer otherdatabuf(otherlen); if (error == TSIGError::BAD_TIME()) { otherdatabuf.writeUint16(now >> 32); otherdatabuf.writeUint32(now & 0xffffffff); } const void* const otherdata = (otherlen == 0) ? NULL : otherdatabuf.getData(); // Then calculate the digest. If state_ is SENT_RESPONSE we are sending // a continued message in the same TCP stream so skip digesting // variables except for time related variables (RFC2845 4.4). impl_->digestTSIGVariables(hmac, TSIGRecord::getClass().getCode(), TSIGRecord::TSIG_TTL, time_signed, DEFAULT_FUDGE, error.getCode(), otherlen, otherdata, impl_->state_ == SENT_RESPONSE); // Get the final digest, update internal state, then finish. vector digest = hmac->sign(impl_->digest_len_); assert(digest.size() <= 0xffff); // cryptolink API should have ensured it. ConstTSIGRecordPtr tsig(new TSIGRecord( impl_->key_.getKeyName(), any::TSIG(impl_->key_.getAlgorithmName(), time_signed, DEFAULT_FUDGE, digest.size(), &digest[0], qid, error.getCode(), otherlen, otherdata))); // Exception free from now on. impl_->previous_digest_.swap(digest); impl_->state_ = (impl_->state_ == INIT) ? SENT_REQUEST : SENT_RESPONSE; return (tsig); } TSIGError TSIGContext::verify(const TSIGRecord* const record, const void* const data, const size_t data_len) { if (impl_->state_ == SENT_RESPONSE) { isc_throw(TSIGContextError, "TSIG verify attempt after sending a response"); } if (record == NULL) { if (impl_->last_sig_dist_ >= 0 && impl_->last_sig_dist_ < 99) { // It is not signed, but in the middle of TCP stream. We just // update the HMAC state and consider this message OK. update(data, data_len); // This one is not signed, the last signed is one message further // now. impl_->last_sig_dist_++; // No digest to return now. Just say it's OK. return (impl_->postVerifyUpdate(TSIGError::NOERROR(), NULL, 0)); } // This case happens when we sent a signed request and have received an // unsigned response. According to RFC2845 Section 4.6 this case should be // considered a "format error" (although the specific error code // wouldn't matter much for the caller). return (impl_->postVerifyUpdate(TSIGError::FORMERR(), NULL, 0)); } const any::TSIG& tsig_rdata = record->getRdata(); // Reject some obviously invalid data if (data_len < MESSAGE_HEADER_LEN + record->getLength()) { isc_throw(InvalidParameter, "TSIG verify: data length is invalid: " << data_len); } if (data == NULL) { isc_throw(InvalidParameter, "TSIG verify: empty data is invalid"); } // This message is signed and we won't throw any more. impl_->last_sig_dist_ = 0; // Check key: whether we first verify it with a known key or we verify // it using the consistent key in the context. If the check fails we are // done with BADKEY. if (impl_->state_ == INIT && impl_->error_ == TSIGError::BAD_KEY()) { return (impl_->postVerifyUpdate(TSIGError::BAD_KEY(), NULL, 0)); } if (impl_->key_.getKeyName() != record->getName() || impl_->key_.getAlgorithmName() != tsig_rdata.getAlgorithm()) { return (impl_->postVerifyUpdate(TSIGError::BAD_KEY(), NULL, 0)); } // Check time: the current time must be in the range of // [time signed - fudge, time signed + fudge]. Otherwise verification // fails with BADTIME. (RFC2845 Section 4.6.2) // Note: for simplicity we don't explicitly catch the case of too small // current time causing underflow. With the fact that fudge is quite // small and (for now) non configurable, it shouldn't be a real concern // in practice. const uint64_t now = getTSIGTime(); if (tsig_rdata.getTimeSigned() + DEFAULT_FUDGE < now || tsig_rdata.getTimeSigned() - DEFAULT_FUDGE > now) { const void* digest = NULL; size_t digest_len = 0; if (impl_->state_ == INIT) { digest = tsig_rdata.getMAC(); digest_len = tsig_rdata.getMACSize(); impl_->previous_timesigned_ = tsig_rdata.getTimeSigned(); } return (impl_->postVerifyUpdate(TSIGError::BAD_TIME(), digest, digest_len)); } // Handling empty MAC. While RFC2845 doesn't explicitly prohibit other // cases, it can only reasonably happen in a response with BADSIG or // BADKEY. We reject other cases as if it were BADSIG to avoid unexpected // acceptance of a bogus signature. This behavior follows the BIND 9 // implementation. if (tsig_rdata.getMACSize() == 0) { TSIGError error = TSIGError(tsig_rdata.getError()); if (error != TSIGError::BAD_SIG() && error != TSIGError::BAD_KEY()) { error = TSIGError::BAD_SIG(); } return (impl_->postVerifyUpdate(error, NULL, 0)); } HMACPtr hmac(impl_->createHMAC()); // If the context has previous MAC (either the Request MAC or its own // previous MAC), digest it. if (impl_->state_ != INIT) { impl_->digestPreviousMAC(hmac); } // Signature length check based on RFC 4635 3.1 if (tsig_rdata.getMACSize() > hmac->getOutputLength()) { // signature length too big return (impl_->postVerifyUpdate(TSIGError::FORMERR(), NULL, 0)); } if ((tsig_rdata.getMACSize() < 10) || (tsig_rdata.getMACSize() < (hmac->getOutputLength() / 2))) { // signature length below minimum return (impl_->postVerifyUpdate(TSIGError::FORMERR(), NULL, 0)); } if (tsig_rdata.getMACSize() < impl_->digest_len_) { // (truncated) signature length too small return (impl_->postVerifyUpdate(TSIGError::BAD_TRUNC(), NULL, 0)); } // // Digest DNS message (excluding the trailing TSIG RR and adjusting the // QID and ARCOUNT header fields) // impl_->digestDNSMessage(hmac, tsig_rdata.getOriginalID(), data, data_len - record->getLength()); // Digest TSIG variables. If state_ is VERIFIED_RESPONSE, it's a // continuation of the same TCP stream and skip digesting them except // for time related variables (RFC2845 4.4). // Note: we use the constant values for RR class and TTL specified // in RFC2845, not received values (we reject other values in constructing // the TSIGRecord). impl_->digestTSIGVariables(hmac, TSIGRecord::getClass().getCode(), TSIGRecord::TSIG_TTL, tsig_rdata.getTimeSigned(), tsig_rdata.getFudge(), tsig_rdata.getError(), tsig_rdata.getOtherLen(), tsig_rdata.getOtherData(), impl_->state_ == VERIFIED_RESPONSE); // Verify the digest with the received signature. if (hmac->verify(tsig_rdata.getMAC(), tsig_rdata.getMACSize())) { return (impl_->postVerifyUpdate(TSIGError::NOERROR(), tsig_rdata.getMAC(), tsig_rdata.getMACSize())); } return (impl_->postVerifyUpdate(TSIGError::BAD_SIG(), NULL, 0)); } bool TSIGContext::lastHadSignature() const { if (impl_->last_sig_dist_ == -1) { isc_throw(TSIGContextError, "No message was verified yet"); } return (impl_->last_sig_dist_ == 0); } void TSIGContext::update(const void* const data, size_t len) { HMACPtr hmac(impl_->createHMAC()); // Use the previous digest and never use it again impl_->digestPreviousMAC(hmac); impl_->previous_digest_.clear(); // Push the message there hmac->update(data, len); impl_->hmac_ = hmac; } } // namespace dns } // namespace isc kea-1.1.0/src/lib/dns/rrtype.h0000664000175000017500000004546612772017075013042 00000000000000/////////////// /////////////// /////////////// THIS FILE IS AUTOMATICALLY GENERATED BY gen-rdatacode.py. /////////////// DO NOT EDIT! /////////////// /////////////// // Copyright (C) 2010-2015 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 RRTYPE_H #define RRTYPE_H 1 #include #include #include #include // Solaris x86 defines DS in , which gets pulled in by Boost #if defined(__sun) && defined(DS) # undef DS #endif namespace isc { namespace util { class InputBuffer; class OutputBuffer; } namespace dns { // forward declarations class AbstractMessageRenderer; /// /// \brief A standard DNS module exception that is thrown if an RRType object /// is being constructed from an unrecognized string. /// class InvalidRRType : public DNSTextError { public: InvalidRRType(const char* file, size_t line, const char* what) : DNSTextError(file, line, what) {} }; /// /// \brief A standard DNS module exception that is thrown if an RRType object /// is being constructed from a incomplete (too short) wire-format data. /// class IncompleteRRType : public isc::dns::Exception { public: IncompleteRRType(const char* file, size_t line, const char* what) : isc::dns::Exception(file, line, what) {} }; /// /// The \c RRType class encapsulates DNS resource record types. /// /// This class manages the 16-bit integer type codes in quite a straightforward /// way. The only non trivial task is to handle textual representations of /// RR types, such as "A", "AAAA", or "TYPE65534". /// /// This class consults a helper \c RRParamRegistry class, which is a registry /// of RR related parameters and has the singleton object. This registry /// provides a mapping between RR type codes and their "well-known" textual /// representations. /// Parameters of RR types defined by DNS protocol standards are automatically /// registered at initialization time and are ensured to be always available for /// applications unless the application explicitly modifies the registry. /// /// For convenience, this class defines constant class objects corresponding to /// standard RR types. These are generally referred to as the form of /// RRType::{type-text}(). /// For example, \c RRType::NS() is an \c RRType object corresponding to the NS /// resource record (type code 2). /// Note that these constants are used through a "proxy" function. /// This is because they may be used to initialize another non-local (e.g. /// global or namespace-scope) static object as follows: /// /// \code /// namespace foo { /// const RRType default_type = RRType::A(); /// } \endcode /// /// In order to ensure that the constant RRType object has been initialized /// before the initialization for \c default_type, we need help from /// the proxy function. /// /// In the current implementation, the initialization of the well-known /// static objects is not thread safe. The same consideration as the /// \c RRParamRegistry class applies. We may extend the implementation so /// that the initialization is ensured to be thread safe in a future version. /// /// Note to developers: since it's expected that some of these constant /// \c RRType objects are frequently used in a performance sensitive path, /// we define these proxy functions as inline. This makes sense only when /// the corresponding static objects are defined only once even if they used /// in different source files. Sufficiently modern compilers should meet /// this assumption, but if we encounter memory bloat due to this problem with /// particular compilers we need to revisit the design or think about /// workaround. class RRType { public: /// /// \name Constructors and Destructor /// //@{ /// Constructor from an integer type code. /// /// This constructor never throws an exception. /// /// \param typecode An 16-bit integer code corresponding to the RRType. explicit RRType(uint16_t typecode) : typecode_(typecode) {} /// Constructor from a string. /// /// A valid string is one of "well-known" textual type representations /// such as "A", "AAAA", or "NS", or in the standard format for "unknown" /// RR types as defined in RFC3597, i.e., "TYPEnnnn". /// /// More precisely, the "well-known" representations are the ones stored /// in the \c RRParamRegistry registry (see the class description). /// /// As for the format of "TYPEnnnn", "nnnn" must represent a valid 16-bit /// unsigned integer, which may contain leading 0's as long as it consists /// of at most 5 characters (inclusive). /// For example, "TYPE1" and "TYPE001" are valid and represent the same /// RR type, but "TYPE65536" and "TYPE000001" are invalid. /// A "TYPEnnnn" representation is valid even if the corresponding type code /// is registered in the \c RRParamRegistry object. For example, both /// "A" and "TYPE1" are valid and represent the same RR type. /// /// All of these representations are case insensitive; "NS" and "ns", and /// "TYPE1" and "type1" are all valid and represent the same RR types, /// respectively. /// /// If the given string is not recognized as a valid representation of /// an RR type, an exception of class \c InvalidRRType will be thrown. /// /// \param typestr A string representation of the \c RRType explicit RRType(const std::string& typestr); /// Constructor from wire-format data. /// /// The \c buffer parameter normally stores a complete DNS message /// containing the RRType to be constructed. The current read position of /// the buffer points to the head of the type. /// /// If the given data does not large enough to contain a 16-bit integer, /// an exception of class \c IncompleteRRType will be thrown. /// /// \param buffer A buffer storing the wire format data. explicit RRType(isc::util::InputBuffer& buffer); /// /// We use the default copy constructor intentionally. //@} /// We use the default copy assignment operator intentionally. /// /// /// \name Converter methods /// //@{ /// \brief Convert the \c RRType to a string. /// /// If a "well known" textual representation for the type code is registered /// in the RR parameter registry (see the class description), that will be /// used as the return value of this method. Otherwise, this method creates /// a new string for an "unknown" RR type in the format defined in RFC3597, /// i.e., "TYPEnnnn", and returns it. /// /// If resource allocation for the string fails, a corresponding standard /// exception will be thrown. /// /// \return A string representation of the \c RRType. const std::string toText() const; /// \brief Render the \c RRType in the wire format. /// /// This method renders the type code in network byte order via \c renderer, /// which encapsulates output buffer and other rendering contexts. /// /// If resource allocation in rendering process fails, a corresponding /// standard exception will be thrown. /// /// \param renderer DNS message rendering context that encapsulates the /// output buffer in which the RRType is to be stored. void toWire(AbstractMessageRenderer& renderer) const; /// \brief Render the \c RRType in the wire format. /// /// This method renders the type code in network byte order into the /// \c buffer. /// /// If resource allocation in rendering process fails, a corresponding /// standard exception will be thrown. /// /// \param buffer An output buffer to store the wire data. void toWire(isc::util::OutputBuffer& buffer) const; //@} /// /// \name Getter Methods /// //@{ /// \brief Returns the RR type code as a 16-bit unsigned integer. /// /// This method never throws an exception. /// /// \return An 16-bit integer code corresponding to the RRType. uint16_t getCode() const { return (typecode_); } //@} /// /// \name Comparison methods /// //@{ /// \brief Return true iff two RRTypes are equal. /// /// Two RRTypes are equal iff their type codes are equal. /// /// This method never throws an exception. /// /// \param other the \c RRType object to compare against. /// \return true if the two RRTypes are equal; otherwise false. bool equals(const RRType& other) const { return (typecode_ == other.typecode_); } /// \brief Same as \c equals(). bool operator==(const RRType& other) const { return (equals(other)); } /// \brief Return true iff two RRTypes are not equal. /// /// This method never throws an exception. /// /// \param other the \c RRType object to compare against. /// \return true if the two RRTypes are not equal; otherwise false. bool nequals(const RRType& other) const { return (typecode_ != other.typecode_); } /// \brief Same as \c nequals(). bool operator!=(const RRType& other) const { return (nequals(other)); } /// \brief Less-than comparison for RRType against \c other /// /// We define the less-than relationship based on their type codes; /// one RRType is less than the other iff the code of the former is less /// than that of the other as unsigned integers. /// The relationship is meaningless in terms of DNS protocol; the only /// reason we define this method is that RRType objects can be stored in /// STL containers without requiring user-defined less-than relationship. /// We therefore don't define other comparison operators. /// /// This method never throws an exception. /// /// \param other the \c RRType object to compare against. /// \return true if \c this RRType is less than the \c other; otherwise /// false. bool operator<(const RRType& other) const { return (typecode_ < other.typecode_); } //@} // BEGIN_WELL_KNOWN_TYPE_DECLARATIONS static const RRType& L32(); static const RRType& NID(); static const RRType& LP(); static const RRType& L64(); static const RRType& UNSPEC(); static const RRType& IXFR(); static const RRType& TSIG(); static const RRType& MAILB(); static const RRType& AXFR(); static const RRType& ANY(); static const RRType& MAILA(); static const RRType& CAA(); static const RRType& URI(); static const RRType& KEY(); static const RRType& SIG(); static const RRType& GPOS(); static const RRType& PX(); static const RRType& RT(); static const RRType& ISDN(); static const RRType& NSAP_PTR(); static const RRType& NSAP(); static const RRType& LOC(); static const RRType& AAAA(); static const RRType& SPF(); static const RRType& MG(); static const RRType& SOA(); static const RRType& MF(); static const RRType& NS(); static const RRType& NSEC3(); static const RRType& NSEC3PARAM(); static const RRType& TLSA(); static const RRType& AFSDB(); static const RRType& HIP(); static const RRType& MINFO(); static const RRType& MX(); static const RRType& TXT(); static const RRType& RP(); static const RRType& Null(); static const RRType& WKS(); static const RRType& PTR(); static const RRType& HINFO(); static const RRType& DLV(); static const RRType& DS(); static const RRType& APL(); static const RRType& OPT(); static const RRType& NSEC(); static const RRType& RRSIG(); static const RRType& IPSECKEY(); static const RRType& SSHFP(); static const RRType& DHCID(); static const RRType& DNSKEY(); static const RRType& X25(); static const RRType& TKEY(); static const RRType& MR(); static const RRType& MB(); static const RRType& CNAME(); static const RRType& MD(); static const RRType& A(); static const RRType& A6(); static const RRType& DNAME(); static const RRType& SRV(); static const RRType& NXT(); static const RRType& KX(); static const RRType& CERT(); static const RRType& NAPTR(); // END_WELL_KNOWN_TYPE_DECLARATIONS private: uint16_t typecode_; }; // BEGIN_WELL_KNOWN_TYPE_DEFINITIONS inline const RRType& RRType::L32() { static RRType rrtype(105); return (rrtype); } inline const RRType& RRType::NID() { static RRType rrtype(104); return (rrtype); } inline const RRType& RRType::LP() { static RRType rrtype(107); return (rrtype); } inline const RRType& RRType::L64() { static RRType rrtype(106); return (rrtype); } inline const RRType& RRType::UNSPEC() { static RRType rrtype(103); return (rrtype); } inline const RRType& RRType::IXFR() { static RRType rrtype(251); return (rrtype); } inline const RRType& RRType::TSIG() { static RRType rrtype(250); return (rrtype); } inline const RRType& RRType::MAILB() { static RRType rrtype(253); return (rrtype); } inline const RRType& RRType::AXFR() { static RRType rrtype(252); return (rrtype); } inline const RRType& RRType::ANY() { static RRType rrtype(255); return (rrtype); } inline const RRType& RRType::MAILA() { static RRType rrtype(254); return (rrtype); } inline const RRType& RRType::CAA() { static RRType rrtype(257); return (rrtype); } inline const RRType& RRType::URI() { static RRType rrtype(256); return (rrtype); } inline const RRType& RRType::KEY() { static RRType rrtype(25); return (rrtype); } inline const RRType& RRType::SIG() { static RRType rrtype(24); return (rrtype); } inline const RRType& RRType::GPOS() { static RRType rrtype(27); return (rrtype); } inline const RRType& RRType::PX() { static RRType rrtype(26); return (rrtype); } inline const RRType& RRType::RT() { static RRType rrtype(21); return (rrtype); } inline const RRType& RRType::ISDN() { static RRType rrtype(20); return (rrtype); } inline const RRType& RRType::NSAP_PTR() { static RRType rrtype(23); return (rrtype); } inline const RRType& RRType::NSAP() { static RRType rrtype(22); return (rrtype); } inline const RRType& RRType::LOC() { static RRType rrtype(29); return (rrtype); } inline const RRType& RRType::AAAA() { static RRType rrtype(28); return (rrtype); } inline const RRType& RRType::SPF() { static RRType rrtype(99); return (rrtype); } inline const RRType& RRType::MG() { static RRType rrtype(8); return (rrtype); } inline const RRType& RRType::SOA() { static RRType rrtype(6); return (rrtype); } inline const RRType& RRType::MF() { static RRType rrtype(4); return (rrtype); } inline const RRType& RRType::NS() { static RRType rrtype(2); return (rrtype); } inline const RRType& RRType::NSEC3() { static RRType rrtype(50); return (rrtype); } inline const RRType& RRType::NSEC3PARAM() { static RRType rrtype(51); return (rrtype); } inline const RRType& RRType::TLSA() { static RRType rrtype(52); return (rrtype); } inline const RRType& RRType::AFSDB() { static RRType rrtype(18); return (rrtype); } inline const RRType& RRType::HIP() { static RRType rrtype(55); return (rrtype); } inline const RRType& RRType::MINFO() { static RRType rrtype(14); return (rrtype); } inline const RRType& RRType::MX() { static RRType rrtype(15); return (rrtype); } inline const RRType& RRType::TXT() { static RRType rrtype(16); return (rrtype); } inline const RRType& RRType::RP() { static RRType rrtype(17); return (rrtype); } inline const RRType& RRType::Null() { static RRType rrtype(10); return (rrtype); } inline const RRType& RRType::WKS() { static RRType rrtype(11); return (rrtype); } inline const RRType& RRType::PTR() { static RRType rrtype(12); return (rrtype); } inline const RRType& RRType::HINFO() { static RRType rrtype(13); return (rrtype); } inline const RRType& RRType::DLV() { static RRType rrtype(32769); return (rrtype); } inline const RRType& RRType::DS() { static RRType rrtype(43); return (rrtype); } inline const RRType& RRType::APL() { static RRType rrtype(42); return (rrtype); } inline const RRType& RRType::OPT() { static RRType rrtype(41); return (rrtype); } inline const RRType& RRType::NSEC() { static RRType rrtype(47); return (rrtype); } inline const RRType& RRType::RRSIG() { static RRType rrtype(46); return (rrtype); } inline const RRType& RRType::IPSECKEY() { static RRType rrtype(45); return (rrtype); } inline const RRType& RRType::SSHFP() { static RRType rrtype(44); return (rrtype); } inline const RRType& RRType::DHCID() { static RRType rrtype(49); return (rrtype); } inline const RRType& RRType::DNSKEY() { static RRType rrtype(48); return (rrtype); } inline const RRType& RRType::X25() { static RRType rrtype(19); return (rrtype); } inline const RRType& RRType::TKEY() { static RRType rrtype(249); return (rrtype); } inline const RRType& RRType::MR() { static RRType rrtype(9); return (rrtype); } inline const RRType& RRType::MB() { static RRType rrtype(7); return (rrtype); } inline const RRType& RRType::CNAME() { static RRType rrtype(5); return (rrtype); } inline const RRType& RRType::MD() { static RRType rrtype(3); return (rrtype); } inline const RRType& RRType::A() { static RRType rrtype(1); return (rrtype); } inline const RRType& RRType::A6() { static RRType rrtype(38); return (rrtype); } inline const RRType& RRType::DNAME() { static RRType rrtype(39); return (rrtype); } inline const RRType& RRType::SRV() { static RRType rrtype(33); return (rrtype); } inline const RRType& RRType::NXT() { static RRType rrtype(30); return (rrtype); } inline const RRType& RRType::KX() { static RRType rrtype(36); return (rrtype); } inline const RRType& RRType::CERT() { static RRType rrtype(37); return (rrtype); } inline const RRType& RRType::NAPTR() { static RRType rrtype(35); return (rrtype); } // END_WELL_KNOWN_TYPE_DEFINITIONS /// /// \brief Insert the \c RRType as a string into stream. /// /// This method convert the \c rrtype into a string and inserts it into the /// output stream \c os. /// /// This function overloads the global operator<< to behave as described in /// ostream::operator<< but applied to \c RRType objects. /// /// \param os A \c std::ostream object on which the insertion operation is /// performed. /// \param rrtype The \c RRType object output by the operation. /// \return A reference to the same \c std::ostream object referenced by /// parameter \c os after the insertion operation. std::ostream& operator<<(std::ostream& os, const RRType& rrtype); } } #endif // RRTYPE_H // Local Variables: // mode: c++ // End: kea-1.1.0/src/lib/dns/rrset.cc0000664000175000017500000002756512772017075013012 00000000000000// Copyright (C) 2010-2015 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 #include #include #include #include #include #include #include #include #include #include #include using namespace std; using namespace isc::dns; using namespace isc::util; using namespace isc::dns::rdata; namespace isc { namespace dns { void AbstractRRset::addRdata(const Rdata& rdata) { addRdata(createRdata(getType(), getClass(), rdata)); } string AbstractRRset::toText() const { string s; RdataIteratorPtr it = getRdataIterator(); // In the case of an empty rrset, just print name, ttl, class, and // type if (it->isLast()) { // But only for class ANY or NONE if (getClass() != RRClass::ANY() && getClass() != RRClass::NONE()) { isc_throw(EmptyRRset, "toText() is attempted for an empty RRset"); } s += getName().toText() + " " + getTTL().toText() + " " + getClass().toText() + " " + getType().toText() + "\n"; return (s); } do { s += getName().toText() + " " + getTTL().toText() + " " + getClass().toText() + " " + getType().toText() + " " + it->getCurrent().toText() + "\n"; it->next(); } while (!it->isLast()); if (getRRsig()) { s += getRRsig()->toText(); } return (s); } namespace { // unnamed namespace // FIXME: This method's code should somehow be unified with // BasicRRsetImpl::toWire() below to avoid duplication. template inline unsigned int rrsetToWire(const AbstractRRset& rrset, T& output, const size_t limit) { unsigned int n = 0; RdataIteratorPtr it = rrset.getRdataIterator(); if (it->isLast()) { // empty rrsets are only allowed for classes ANY and NONE if (rrset.getClass() != RRClass::ANY() && rrset.getClass() != RRClass::NONE()) { isc_throw(EmptyRRset, "toWire() is attempted for an empty RRset"); } // For an empty RRset, write the name, type, class and TTL once, // followed by empty rdata. rrset.getName().toWire(output); rrset.getType().toWire(output); rrset.getClass().toWire(output); rrset.getTTL().toWire(output); output.writeUint16(0); // Still counts as 1 'rr'; it does show up in the message return (1); } // sort the set of Rdata based on rrset-order and sortlist, and possible // other options. Details to be considered. do { const size_t pos0 = output.getLength(); assert(pos0 < 65536); rrset.getName().toWire(output); rrset.getType().toWire(output); rrset.getClass().toWire(output); rrset.getTTL().toWire(output); const size_t pos = output.getLength(); output.skip(sizeof(uint16_t)); // leave the space for RDLENGTH it->getCurrent().toWire(output); output.writeUint16At(output.getLength() - pos - sizeof(uint16_t), pos); if (limit > 0 && output.getLength() > limit) { // truncation is needed output.trim(output.getLength() - pos0); return (n); } it->next(); ++n; } while (!it->isLast()); return (n); } } // end of unnamed namespace unsigned int AbstractRRset::toWire(OutputBuffer& buffer) const { return (rrsetToWire(*this, buffer, 0)); } unsigned int AbstractRRset::toWire(AbstractMessageRenderer& renderer) const { const unsigned int rrs_written = rrsetToWire( *this, renderer, renderer.getLengthLimit()); if (getRdataCount() > rrs_written) { renderer.setTruncated(); } return (rrs_written); } bool AbstractRRset::isSameKind(const AbstractRRset& other) const { // Compare classes last as they're likely to be identical. Compare // names late in the list too, as these are expensive. So we compare // types first, names second and classes last. return (getType() == other.getType() && getName() == other.getName() && getClass() == other.getClass()); } ostream& operator<<(ostream& os, const AbstractRRset& rrset) { os << rrset.toText(); return (os); } /// \brief This encapsulates the actual implementation of the \c BasicRRset /// class. It's hidden from applications. class BasicRRsetImpl { public: BasicRRsetImpl(const Name& name, const RRClass& rrclass, const RRType& rrtype, const RRTTL& ttl) : name_(name), rrclass_(rrclass), rrtype_(rrtype), ttl_(ttl) {} unsigned int toWire(AbstractMessageRenderer& renderer, size_t limit) const; Name name_; RRClass rrclass_; RRType rrtype_; RRTTL ttl_; // XXX: "list" is not a good name: It in fact isn't a list; more conceptual // name than a data structure name is generally better. But since this // is only used in the internal implementation we'll live with it. vector rdatalist_; }; // FIXME: This method's code should somehow be unified with // rrsetToWire() above to avoid duplication. unsigned int BasicRRsetImpl::toWire(AbstractMessageRenderer& renderer, size_t limit) const { if (rdatalist_.empty()) { // empty rrsets are only allowed for classes ANY and NONE if (rrclass_ != RRClass::ANY() && rrclass_ != RRClass::NONE()) { isc_throw(EmptyRRset, "toWire() is attempted for an empty RRset"); } // For an empty RRset, write the name, type, class and TTL once, // followed by empty rdata. name_.toWire(renderer); rrtype_.toWire(renderer); rrclass_.toWire(renderer); ttl_.toWire(renderer); renderer.writeUint16(0); // Still counts as 1 'rr'; it does show up in the message return (1); } unsigned int n = 0; // sort the set of Rdata based on rrset-order and sortlist, and possible // other options. Details to be considered. BOOST_FOREACH(const ConstRdataPtr& rdata, rdatalist_) { const size_t pos0 = renderer.getLength(); assert(pos0 < 65536); name_.toWire(renderer); rrtype_.toWire(renderer); rrclass_.toWire(renderer); ttl_.toWire(renderer); const size_t pos = renderer.getLength(); renderer.skip(sizeof(uint16_t)); // leave the space for RDLENGTH rdata->toWire(renderer); renderer.writeUint16At(renderer.getLength() - pos - sizeof(uint16_t), pos); if (limit > 0 && renderer.getLength() > limit) { // truncation is needed renderer.trim(renderer.getLength() - pos0); return (n); } ++n; } return (n); } BasicRRset::BasicRRset(const Name& name, const RRClass& rrclass, const RRType& rrtype, const RRTTL& ttl) { impl_ = new BasicRRsetImpl(name, rrclass, rrtype, ttl); } BasicRRset::~BasicRRset() { delete impl_; } void BasicRRset::addRdata(ConstRdataPtr rdata) { impl_->rdatalist_.push_back(rdata); } void BasicRRset::addRdata(const Rdata& rdata) { AbstractRRset::addRdata(rdata); } void BasicRRset::addRdata(const std::string& rdata_str) { addRdata(createRdata(getType(), getClass(), rdata_str)); } unsigned int BasicRRset::getRdataCount() const { return (impl_->rdatalist_.size()); } const Name& BasicRRset::getName() const { return (impl_->name_); } const RRClass& BasicRRset::getClass() const { return (impl_->rrclass_); } const RRType& BasicRRset::getType() const { return (impl_->rrtype_); } const RRTTL& BasicRRset::getTTL() const { return (impl_->ttl_); } void BasicRRset::setTTL(const RRTTL& ttl) { impl_->ttl_ = ttl; } string BasicRRset::toText() const { return (AbstractRRset::toText()); } uint16_t BasicRRset::getLength() const { uint16_t length = 0; RdataIteratorPtr it = getRdataIterator(); if (it->isLast()) { // empty rrsets are only allowed for classes ANY and NONE if (getClass() != RRClass::ANY() && getClass() != RRClass::NONE()) { isc_throw(EmptyRRset, "getLength() is attempted for an empty RRset"); } // For an empty RRset, write the name, type, class and TTL once, // followed by empty rdata. length += getName().getLength(); length += 2; // TYPE field length += 2; // CLASS field length += 4; // TTL field length += 2; // RDLENGTH field (=0 in wire format) return (length); } do { // This is a size_t as some of the following additions may // overflow due to a programming mistake somewhere. size_t rrlen = 0; rrlen += getName().getLength(); rrlen += 2; // TYPE field rrlen += 2; // CLASS field rrlen += 4; // TTL field rrlen += 2; // RDLENGTH field rrlen += it->getCurrent().getLength(); assert(length + rrlen < 65536); length += rrlen; it->next(); } while (!it->isLast()); return (length); } unsigned int BasicRRset::toWire(OutputBuffer& buffer) const { return (AbstractRRset::toWire(buffer)); } unsigned int BasicRRset::toWire(AbstractMessageRenderer& renderer) const { const unsigned int rrs_written = impl_->toWire(renderer, renderer.getLengthLimit()); if (impl_->rdatalist_.size() > rrs_written) { renderer.setTruncated(); } return (rrs_written); } RRset::RRset(const Name& name, const RRClass& rrclass, const RRType& rrtype, const RRTTL& ttl) : BasicRRset(name, rrclass, rrtype, ttl) { rrsig_ = RRsetPtr(); } RRset::~RRset() {} unsigned int RRset::getRRsigDataCount() const { if (rrsig_) { return (rrsig_->getRdataCount()); } else { return (0); } } uint16_t RRset::getLength() const { uint16_t length = BasicRRset::getLength(); if (rrsig_) { const uint16_t rrsigs_length = rrsig_->getLength(); // the uint16_ts are promoted to ints during addition below, so // it won't overflow a 16-bit register. assert(length + rrsigs_length < 65536); length += rrsigs_length; } return (length); } unsigned int RRset::toWire(OutputBuffer& buffer) const { unsigned int rrs_written = BasicRRset::toWire(buffer); if (getRdataCount() > rrs_written) { return (rrs_written); } if (rrsig_) { rrs_written += rrsig_->toWire(buffer); } return (rrs_written); } unsigned int RRset::toWire(AbstractMessageRenderer& renderer) const { unsigned int rrs_written = BasicRRset::toWire(renderer); if (getRdataCount() > rrs_written) { return (rrs_written); } if (rrsig_) { rrs_written += rrsig_->toWire(renderer); if (getRdataCount() + getRRsigDataCount() > rrs_written) { renderer.setTruncated(); } } return (rrs_written); } namespace { class BasicRdataIterator : public RdataIterator { private: BasicRdataIterator() {} public: BasicRdataIterator(const std::vector& datavector) : datavector_(&datavector), it_(datavector_->begin()) {} ~BasicRdataIterator() {} virtual void first() { it_ = datavector_->begin(); } virtual void next() { ++it_; } virtual const rdata::Rdata& getCurrent() const { return (**it_); } virtual bool isLast() const { return (it_ == datavector_->end()); } private: const std::vector* datavector_; std::vector::const_iterator it_; }; } RdataIteratorPtr BasicRRset::getRdataIterator() const { return (RdataIteratorPtr(new BasicRdataIterator(impl_->rdatalist_))); } } } kea-1.1.0/src/lib/dns/rdataclass.cc0000664000175000017500000057412112772017075013767 00000000000000/////////////// /////////////// /////////////// THIS FILE IS AUTOMATICALLY GENERATED BY gen-rdatacode.py. /////////////// DO NOT EDIT! /////////////// /////////////// // Copyright (C) 2010-2015 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 #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; using boost::lexical_cast; using namespace isc::util; using namespace isc::util::encode; using namespace isc::dns; using isc::dns::rdata::generic::detail::createNameFromLexer; namespace isc { namespace dns { namespace rdata { namespace any { // straightforward representation of TSIG RDATA fields struct TSIGImpl { TSIGImpl(const Name& algorithm, uint64_t time_signed, uint16_t fudge, vector& mac, uint16_t original_id, uint16_t error, vector& other_data) : algorithm_(algorithm), time_signed_(time_signed), fudge_(fudge), mac_(mac), original_id_(original_id), error_(error), other_data_(other_data) {} TSIGImpl(const Name& algorithm, uint64_t time_signed, uint16_t fudge, size_t macsize, const void* mac, uint16_t original_id, uint16_t error, size_t other_len, const void* other_data) : algorithm_(algorithm), time_signed_(time_signed), fudge_(fudge), mac_(static_cast(mac), static_cast(mac) + macsize), original_id_(original_id), error_(error), other_data_(static_cast(other_data), static_cast(other_data) + other_len) {} template void toWireCommon(Output& output) const; const Name algorithm_; const uint64_t time_signed_; const uint16_t fudge_; const vector mac_; const uint16_t original_id_; const uint16_t error_; const vector other_data_; }; // helper function for string and lexer constructors TSIGImpl* TSIG::constructFromLexer(MasterLexer& lexer, const Name* origin) { const Name& algorithm = createNameFromLexer(lexer, origin ? origin : &Name::ROOT_NAME()); const Name& canonical_algorithm_name = (algorithm == TSIGKey::HMACMD5_SHORT_NAME()) ? TSIGKey::HMACMD5_NAME() : algorithm; const string& time_txt = lexer.getNextToken(MasterToken::STRING).getString(); uint64_t time_signed; try { time_signed = boost::lexical_cast(time_txt); } catch (const boost::bad_lexical_cast&) { isc_throw(InvalidRdataText, "Invalid TSIG Time"); } if ((time_signed >> 48) != 0) { isc_throw(InvalidRdataText, "TSIG Time out of range"); } const uint32_t fudge = lexer.getNextToken(MasterToken::NUMBER).getNumber(); if (fudge > 0xffff) { isc_throw(InvalidRdataText, "TSIG Fudge out of range"); } const uint32_t macsize = lexer.getNextToken(MasterToken::NUMBER).getNumber(); if (macsize > 0xffff) { isc_throw(InvalidRdataText, "TSIG MAC Size out of range"); } const string& mac_txt = (macsize > 0) ? lexer.getNextToken(MasterToken::STRING).getString() : ""; vector mac; decodeBase64(mac_txt, mac); if (mac.size() != macsize) { isc_throw(InvalidRdataText, "TSIG MAC Size and data are inconsistent"); } const uint32_t orig_id = lexer.getNextToken(MasterToken::NUMBER).getNumber(); if (orig_id > 0xffff) { isc_throw(InvalidRdataText, "TSIG Original ID out of range"); } const string& error_txt = lexer.getNextToken(MasterToken::STRING).getString(); uint32_t error = 0; // XXX: In the initial implementation we hardcode the mnemonics. // We'll soon generalize this. if (error_txt == "NOERROR") { error = Rcode::NOERROR_CODE; } else if (error_txt == "BADSIG") { error = TSIGError::BAD_SIG_CODE; } else if (error_txt == "BADKEY") { error = TSIGError::BAD_KEY_CODE; } else if (error_txt == "BADTIME") { error = TSIGError::BAD_TIME_CODE; } else if (error_txt == "BADMODE") { error = TSIGError::BAD_MODE_CODE; } else if (error_txt == "BADNAME") { error = TSIGError::BAD_NAME_CODE; } else if (error_txt == "BADALG") { error = TSIGError::BAD_ALG_CODE; } else if (error_txt == "BADTRUNC") { error = TSIGError::BAD_TRUNC_CODE; } else { /// we cast to uint32_t and range-check, because casting directly to /// uint16_t will convert negative numbers to large positive numbers try { error = boost::lexical_cast(error_txt); } catch (const boost::bad_lexical_cast&) { isc_throw(InvalidRdataText, "Invalid TSIG Error"); } if (error > 0xffff) { isc_throw(InvalidRdataText, "TSIG Error out of range"); } } const uint32_t otherlen = lexer.getNextToken(MasterToken::NUMBER).getNumber(); if (otherlen > 0xffff) { isc_throw(InvalidRdataText, "TSIG Other Len out of range"); } const string otherdata_txt = (otherlen > 0) ? lexer.getNextToken(MasterToken::STRING).getString() : ""; vector other_data; decodeBase64(otherdata_txt, other_data); if (other_data.size() != otherlen) { isc_throw(InvalidRdataText, "TSIG Other Data length does not match Other Len"); } // RFC2845 says Other Data is "empty unless Error == BADTIME". // However, we don't enforce that. return (new TSIGImpl(canonical_algorithm_name, time_signed, fudge, mac, orig_id, error, other_data)); } /// \brief Constructor from string. /// /// The given string must represent a valid TSIG RDATA. There can be extra /// space characters at the beginning or end of the text (which are simply /// ignored), but other extra text, including a new line, will make the /// construction fail with an exception. /// /// \c tsig_str must be formatted as follows: /// \code