diff options
Diffstat (limited to '')
327 files changed, 10187 insertions, 8427 deletions
diff --git a/Doxyfile.in b/Doxyfile.in index da386e3..51f724b 100644 --- a/Doxyfile.in +++ b/Doxyfile.in @@ -1,4 +1,4 @@ -# Doxyfile 1.8.17 +# Doxyfile 1.9.1 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. @@ -17,11 +17,11 @@ # 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 https://www.gnu.org/software/libiconv -# for the list of possible encodings. +# This tag specifies the encoding used for all characters in the configuration +# 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 +# https://www.gnu.org/software/libiconv/ for the list of possible encodings. # The default value is: UTF-8. DOXYFILE_ENCODING = UTF-8 @@ -93,6 +93,14 @@ ALLOW_UNICODE_NAMES = NO OUTPUT_LANGUAGE = English +# The OUTPUT_TEXT_DIRECTION tag is used to specify the direction in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all generated output in the proper direction. +# Possible values are: None, LTR, RTL and Context. +# The default value is: None. + +OUTPUT_TEXT_DIRECTION = None + # If the BRIEF_MEMBER_DESC tag is set to YES, 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. @@ -189,6 +197,16 @@ SHORT_NAMES = NO JAVADOC_AUTOBRIEF = NO +# If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line +# such as +# /*************** +# as being the beginning of a Javadoc-style comment "banner". If set to NO, the +# Javadoc-style will behave just like regular comments and it will not be +# interpreted by doxygen. +# The default value is: NO. + +JAVADOC_BANNER = NO + # 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 Qt-style will behave just like regular Qt-style comments (thus @@ -209,6 +227,14 @@ QT_AUTOBRIEF = NO MULTILINE_CPP_IS_BRIEF = NO +# By default Python docstrings are displayed as preformatted text and doxygen's +# special commands cannot be used. By setting PYTHON_DOCSTRING to NO the +# doxygen's special commands can be used and the contents of the docstring +# documentation blocks is shown as doxygen documentation. +# The default value is: YES. + +PYTHON_DOCSTRING = YES + # If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the # documentation from any documented member that it re-implements. # The default value is: YES. @@ -236,16 +262,15 @@ TAB_SIZE = 8 # 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. +# newlines (in the resulting output). You can put ^^ in the value part of an +# alias to insert a newline as if a physical newline was in the original file. +# When you need a literal { or } or , in the value part of an alias you have to +# escape them by means of a backslash (\), this can lead to conflicts with the +# commands \{ and \} for these it is advised to use the version @{ and @} or use +# a double escape (\\{ and \\}) 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 @@ -274,28 +299,40 @@ OPTIMIZE_FOR_FORTRAN = NO OPTIMIZE_OUTPUT_VHDL = NO +# Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice +# sources only. Doxygen will then generate output that is more tailored for that +# language. For instance, namespaces will be presented as modules, types will be +# separated into more groups, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_SLICE = 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, -# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran: -# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran: -# Fortran. In the later case the parser tries to guess whether the code is fixed -# or free formatted code, this is the default for Fortran type files), VHDL. 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. +# language is one of the parsers supported by doxygen: IDL, Java, JavaScript, +# Csharp (C#), C, C++, D, PHP, md (Markdown), Objective-C, Python, Slice, VHDL, +# Fortran (fixed format Fortran: FortranFixed, free formatted Fortran: +# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser +# tries to guess whether the code is fixed or free formatted code, this is the +# default for Fortran type files). 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. +# the files are not read by doxygen. When specifying no_extension you should add +# * to the FILE_PATTERNS. +# +# Note see also the list of default file extension mappings. EXTENSION_MAPPING = # If the MARKDOWN_SUPPORT tag is enabled 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. +# documentation. See https://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. @@ -303,6 +340,15 @@ EXTENSION_MAPPING = MARKDOWN_SUPPORT = YES +# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up +# to that level are automatically included in the table of contents, even if +# they do not have an id attribute. +# Note: This feature currently applies only to Markdown headings. +# Minimum value: 0, maximum value: 99, default value: 5. +# This tag requires that the tag MARKDOWN_SUPPORT is set to YES. + +TOC_INCLUDE_HEADINGS = 5 + # 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 putting a % sign in front of the word or @@ -328,7 +374,7 @@ BUILTIN_STL_SUPPORT = NO CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip (see: -# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen +# https://www.riverbankcomputing.com/software/sip/intro) 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. @@ -414,6 +460,19 @@ TYPEDEF_HIDES_STRUCT = YES LOOKUP_CACHE_SIZE = 0 +# The NUM_PROC_THREADS specifies the number threads doxygen is allowed to use +# during processing. When set to 0 doxygen will based this on the number of +# cores available in the system. You can set it explicitly to a value larger +# than 0 to get more control over the balance between CPU load and processing +# speed. At this moment only the input processing can be done using multiple +# threads. Since this is still an experimental feature the default is set to 1, +# which efficively disables parallel processing. Please report any issues you +# encounter. Generating dot graphs in parallel is controlled by the +# DOT_NUM_THREADS setting. +# Minimum value: 0, maximum value: 32, default value: 1. + +NUM_PROC_THREADS = 1 + #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- @@ -434,6 +493,12 @@ EXTRACT_ALL = YES EXTRACT_PRIVATE = NO +# If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual +# methods of a class will be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIV_VIRTUAL = 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. @@ -471,6 +536,13 @@ EXTRACT_LOCAL_METHODS = NO EXTRACT_ANON_NSPACES = NO +# If this flag is set to YES, the name of an unnamed parameter in a declaration +# will be determined by the corresponding definition. By default unnamed +# parameters remain unnamed in the output. +# The default value is: YES. + +RESOLVE_UNNAMED_PARAMS = YES + # If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all # undocumented members inside documented classes or files. If set to NO these # members will be included in the various overviews, but no documentation @@ -488,8 +560,8 @@ HIDE_UNDOC_MEMBERS = 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, these declarations will be -# included in the documentation. +# declarations. If set to NO, these declarations will be included in the +# documentation. # The default value is: NO. HIDE_FRIEND_COMPOUNDS = NO @@ -508,11 +580,18 @@ HIDE_IN_BODY_DOCS = 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. +# With the correct setting of option CASE_SENSE_NAMES doxygen will better be +# able to match the capabilities of the underlying filesystem. In case the +# filesystem is case sensitive (i.e. it supports files in the same directory +# whose names only differ in casing), the option must be set to YES to properly +# deal with such files in case they appear in the input. For filesystems that +# are not case sensitive the option should be be set to NO to properly deal with +# output files written for symbols that only differ in casing, such as for two +# classes, one named CLASS and the other named Class, and to also support +# references to files without having to specify the exact matching casing. On +# Windows (including Cygwin) and MacOS, users should typically set this option +# to NO, whereas on Linux or other Unix flavors it should typically be set to +# YES. # The default value is: system dependent. CASE_SENSE_NAMES = NO @@ -699,7 +778,7 @@ LAYOUT_FILE = doc/doxygen/DoxygenLayout.xml # The CITE_BIB_FILES tag can be used to specify one or more bib files containing # the reference definitions. This must be a list of .bib files. The .bib # extension is automatically appended if omitted. This requires the bibtex tool -# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. +# to be installed. See also https://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. See also \cite for info how to create references. @@ -744,13 +823,17 @@ WARN_IF_DOC_ERROR = YES # This 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, doxygen will only warn about wrong or incomplete -# parameter documentation, but not about the absence of documentation. +# parameter documentation, but not about the absence of documentation. If +# EXTRACT_ALL is set to YES then this flag will automatically be disabled. # The default value is: NO. WARN_NO_PARAMDOC = NO # If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when -# a warning is encountered. +# a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS +# then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but +# at the end of the doxygen process doxygen will return with a non-zero status. +# Possible values are: NO, YES and FAIL_ON_WARNINGS. # The default value is: NO. WARN_AS_ERROR = NO @@ -790,8 +873,8 @@ INPUT = doc/doxygen/Doxy.page.h \ # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses # libiconv (or the iconv built into libc) for the transcoding. See the libiconv -# documentation (see: https://www.gnu.org/software/libiconv) for the list of -# possible encodings. +# documentation (see: +# https://www.gnu.org/software/libiconv/) for the list of possible encodings. # The default value is: UTF-8. INPUT_ENCODING = UTF-8 @@ -804,11 +887,15 @@ INPUT_ENCODING = UTF-8 # need to set EXTENSION_MAPPING for the extension otherwise the files are not # read by doxygen. # +# Note the list of default checked file patterns might differ from the list of +# default file extension mappings. +# # 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, *.pyw, *.f90, *.f, *.for, *.tcl, -# *.vhd, *.vhdl, *.ucf, *.qsf, *.as and *.js. +# *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C comment), +# *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd, *.vhdl, +# *.ucf, *.qsf and *.ice. FILE_PATTERNS = *.h @@ -963,7 +1050,7 @@ INLINE_SOURCES = NO 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. +# entity all documented functions referencing it will be listed. # The default value is: NO. REFERENCED_BY_RELATION = NO @@ -1000,7 +1087,7 @@ SOURCE_TOOLTIPS = YES # # To use it do the following: # - Install the latest version of global -# - Enable SOURCE_BROWSER and USE_HTAGS in the config file +# - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file # - Make sure the INPUT points to the root of the source tree # - Run doxygen as normal # @@ -1023,16 +1110,22 @@ USE_HTAGS = NO VERBATIM_HEADERS = YES # If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the -# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the -# cost of reduced performance. This can be particularly helpful with template -# rich C++ code for which doxygen's built-in parser lacks the necessary type -# information. +# clang parser (see: +# http://clang.llvm.org/) for more accurate parsing at the cost of reduced +# performance. This can be particularly helpful with template rich C++ code for +# which doxygen's built-in parser lacks the necessary type information. # Note: The availability of this option depends on whether or not doxygen was -# generated with the -Duse-libclang=ON option for CMake. +# generated with the -Duse_libclang=ON option for CMake. # The default value is: NO. CLANG_ASSISTED_PARSING = NO +# If clang assisted parsing is enabled and the CLANG_ADD_INC_PATHS tag is set to +# YES then doxygen will add the directory of each input to the include path. +# The default value is: YES. + +CLANG_ADD_INC_PATHS = YES + # If clang assisted parsing is enabled you can provide the compiler with command # line options that you would normally use when invoking the compiler. Note that # the include paths will already be set by doxygen for the files and directories @@ -1041,6 +1134,19 @@ CLANG_ASSISTED_PARSING = NO CLANG_OPTIONS = +# If clang assisted parsing is enabled you can provide the clang parser with the +# path to the directory containing a file called compile_commands.json. This +# file is the compilation database (see: +# http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) containing the +# options used when the source files were built. This is equivalent to +# specifying the -p option to a clang tool, such as clang-check. These options +# will then be passed to the parser. Any options specified with CLANG_OPTIONS +# will be added as well. +# Note: The availability of this option depends on whether or not doxygen was +# generated with the -Duse_libclang=ON option for CMake. + +CLANG_DATABASE_PATH = + #--------------------------------------------------------------------------- # Configuration options related to the alphabetical class index #--------------------------------------------------------------------------- @@ -1052,13 +1158,6 @@ CLANG_OPTIONS = ALPHABETICAL_INDEX = YES -# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in -# which the alphabetical index 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 = 5 - # 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 a prefix (or a list of prefixes) that should be ignored @@ -1159,7 +1258,7 @@ 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 +# https://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. @@ -1195,6 +1294,17 @@ HTML_COLORSTYLE_GAMMA = 80 HTML_TIMESTAMP = YES +# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML +# documentation will contain a main index with vertical navigation menus that +# are dynamically created via JavaScript. If disabled, the navigation index will +# consists of multiple levels of tabs that are statically embedded in every HTML +# page. Disable this option to support browsers that do not have JavaScript, +# like the Qt help browser. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_MENUS = 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. @@ -1218,13 +1328,14 @@ 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 (see: http://developer.apple.com/tools/xcode/), 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 +# environment (see: +# https://developer.apple.com/xcode/), 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. +# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy +# genXcode/_index.html for more information. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. @@ -1263,8 +1374,8 @@ DOCSET_PUBLISHER_NAME = Publisher # If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three # additional HTML index files: index.hhp, index.hhc, and index.hhk. The # index.hhp is a project file that can be read by Microsoft's HTML Help Workshop -# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on -# Windows. +# (see: +# https://www.microsoft.com/en-us/download/details.aspx?id=21138) on Windows. # # The HTML Help Workshop contains a compiler that can convert all HTML output # generated by doxygen into a single compiled HTML file (.chm). Compiled HTML @@ -1294,7 +1405,7 @@ CHM_FILE = HHC_LOCATION = # 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). +# (YES) or that it should be included in the main .chm file (NO). # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. @@ -1339,7 +1450,8 @@ QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help # Project output. For more information please see Qt Help Project / Namespace -# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace). +# (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace). # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_QHP is set to YES. @@ -1347,8 +1459,8 @@ QHP_NAMESPACE = org.doxygen.Project # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt # Help Project output. For more information please see Qt Help Project / Virtual -# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual- -# folders). +# Folders (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-folders). # The default value is: doc. # This tag requires that the tag GENERATE_QHP is set to YES. @@ -1356,30 +1468,30 @@ QHP_VIRTUAL_FOLDER = doc # If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom # filter to add. For more information please see Qt Help Project / Custom -# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- -# filters). +# Filters (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_NAME = # The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the # custom filter to add. For more information please see Qt Help Project / Custom -# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- -# filters). +# Filters (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#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 (see: -# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_SECT_FILTER_ATTRS = -# 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. +# The QHG_LOCATION tag can be used to specify the location (absolute path +# including file name) 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 = @@ -1456,6 +1568,17 @@ TREEVIEW_WIDTH = 250 EXT_LINKS_IN_WINDOW = NO +# If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg +# tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see +# https://inkscape.org) to generate formulas as SVG images instead of PNGs for +# the HTML output. These images will generally look nicer at scaled resolutions. +# Possible values are: png (the default) and svg (looks nicer but requires the +# pdf2svg or inkscape tool). +# The default value is: png. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FORMULA_FORMAT = png + # Use this tag to change the font size of LaTeX formulas included as images in # the HTML documentation. When you change the font size after a successful # doxygen run you need to manually remove any form_*.png images from the HTML @@ -1476,8 +1599,14 @@ FORMULA_FONTSIZE = 10 FORMULA_TRANSPARENT = YES +# The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands +# to create new LaTeX commands to be used in formulas as building blocks. See +# the section "Including formulas" for details. + +FORMULA_MACROFILE = + # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see -# http://www.mathjax.org) which uses client side Javascript for the rendering +# https://www.mathjax.org) which uses client side JavaScript for the rendering # instead of using pre-rendered 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 @@ -1489,7 +1618,7 @@ 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. +# http://docs.mathjax.org/en/v2.7-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. @@ -1504,8 +1633,8 @@ MATHJAX_FORMAT = HTML-CSS # 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. +# MathJax from https://www.mathjax.org before deployment. +# The default value is: https://cdn.jsdelivr.net/npm/mathjax@2. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest @@ -1519,7 +1648,8 @@ 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 +# (see: +# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. For an # example see the documentation. # This tag requires that the tag USE_MATHJAX is set to YES. @@ -1547,7 +1677,7 @@ MATHJAX_CODEFILE = SEARCHENGINE = YES # When the SERVER_BASED_SEARCH tag is enabled the search engine will be -# implemented using a web server instead of a web client using Javascript. There +# implemented using a web server instead of a web client using JavaScript. There # are two flavors of web server based searching depending on the EXTERNAL_SEARCH # setting. When disabled, doxygen will generate a PHP script for searching and # an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing @@ -1566,7 +1696,8 @@ SERVER_BASED_SEARCH = NO # # 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/). +# Xapian (see: +# https://xapian.org/). # # See the section "External Indexing and Searching" for details. # The default value is: NO. @@ -1579,8 +1710,9 @@ EXTERNAL_SEARCH = NO # # 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. +# Xapian (see: +# https://xapian.org/). See the section "External Indexing and Searching" for +# details. # This tag requires that the tag SEARCHENGINE is set to YES. SEARCHENGINE_URL = @@ -1631,21 +1763,35 @@ LATEX_OUTPUT = latex # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. # -# 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. +# Note that when not enabling USE_PDFLATEX the default is latex when enabling +# USE_PDFLATEX the default is pdflatex and when in the later case latex is +# chosen this is overwritten by pdflatex. For specific output languages the +# default can have been set differently, this depends on the implementation of +# the output language. # 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. +# Note: This tag is used in the Makefile / make.bat. +# See also: LATEX_MAKEINDEX_CMD for the part in the generated output file +# (.tex). # The default file is: makeindex. # This tag requires that the tag GENERATE_LATEX is set to YES. MAKEINDEX_CMD_NAME = makeindex +# The LATEX_MAKEINDEX_CMD tag can be used to specify the command name to +# generate index for LaTeX. In case there is no backslash (\) as first character +# it will be automatically added in the LaTeX code. +# Note: This tag is used in the generated output file (.tex). +# See also: MAKEINDEX_CMD_NAME for the part in the Makefile / make.bat. +# The default value is: makeindex. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_MAKEINDEX_CMD = 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. @@ -1661,7 +1807,7 @@ COMPACT_LATEX = NO # The default value is: a4. # This tag requires that the tag GENERATE_LATEX is set to YES. -PAPER_TYPE = a4wide +PAPER_TYPE = a4 # The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names # that should be included in the LaTeX output. The package can be specified just @@ -1730,9 +1876,11 @@ LATEX_EXTRA_FILES = PDF_HYPERLINKS = YES -# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate -# the PDF file directly from the LaTeX files. Set this option to YES, to get a -# higher quality PDF documentation. +# If the USE_PDFLATEX tag is set to YES, doxygen will use the engine as +# specified with LATEX_CMD_NAME to generate the PDF file directly from the LaTeX +# files. Set this option to YES, to get a higher quality PDF documentation. +# +# See also section LATEX_CMD_NAME for selecting the engine. # The default value is: YES. # This tag requires that the tag GENERATE_LATEX is set to YES. @@ -1766,7 +1914,7 @@ 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. See -# http://en.wikipedia.org/wiki/BibTeX and \cite for more info. +# https://en.wikipedia.org/wiki/BibTeX and \cite for more info. # The default value is: plain. # This tag requires that the tag GENERATE_LATEX is set to YES. @@ -1780,6 +1928,14 @@ LATEX_BIB_STYLE = plain LATEX_TIMESTAMP = NO +# The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute) +# path from which the emoji images will be read. If a relative path is entered, +# it will be relative to the LATEX_OUTPUT directory. If left blank the +# LATEX_OUTPUT directory will be used. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_EMOJI_DIRECTORY = + #--------------------------------------------------------------------------- # Configuration options related to the RTF output #--------------------------------------------------------------------------- @@ -1819,9 +1975,9 @@ COMPACT_RTF = NO RTF_HYPERLINKS = NO -# Load stylesheet 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. +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# configuration file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. # # See also section "Doxygen usage" for information on how to generate the # default style sheet that doxygen normally uses. @@ -1830,8 +1986,8 @@ RTF_HYPERLINKS = NO RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an RTF document. Syntax is -# similar to doxygen's config file. A template extensions file can be generated -# using doxygen -e rtf extensionFile. +# similar to doxygen's configuration file. A template extensions file can be +# generated using doxygen -e rtf extensionFile. # This tag requires that the tag GENERATE_RTF is set to YES. RTF_EXTENSIONS_FILE = @@ -1917,6 +2073,13 @@ XML_OUTPUT = xml XML_PROGRAMLISTING = YES +# If the XML_NS_MEMB_FILE_SCOPE tag is set to YES, doxygen will include +# namespace members in file scope as well, matching the HTML output. +# The default value is: NO. +# This tag requires that the tag GENERATE_XML is set to YES. + +XML_NS_MEMB_FILE_SCOPE = NO + #--------------------------------------------------------------------------- # Configuration options related to the DOCBOOK output #--------------------------------------------------------------------------- @@ -1949,9 +2112,9 @@ DOCBOOK_PROGRAMLISTING = NO #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an -# AutoGen Definitions (see http://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. +# AutoGen Definitions (see http://autogen.sourceforge.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 @@ -2228,10 +2391,32 @@ UML_LOOK = NO # but if the number exceeds 15, the total amount of fields shown is limited to # 10. # Minimum value: 0, maximum value: 100, default value: 10. -# This tag requires that the tag HAVE_DOT is set to YES. +# This tag requires that the tag UML_LOOK is set to YES. UML_LIMIT_NUM_FIELDS = 10 +# If the DOT_UML_DETAILS tag is set to NO, doxygen will show attributes and +# methods without types and arguments in the UML graphs. If the DOT_UML_DETAILS +# tag is set to YES, doxygen will add type and arguments for attributes and +# methods in the UML graphs. If the DOT_UML_DETAILS tag is set to NONE, doxygen +# will not generate fields with class member information in the UML graphs. The +# class diagrams will look similar to the default class diagrams but using UML +# notation for the relationships. +# Possible values are: NO, YES and NONE. +# The default value is: NO. +# This tag requires that the tag UML_LOOK is set to YES. + +DOT_UML_DETAILS = NO + +# The DOT_WRAP_THRESHOLD tag can be used to set the maximum number of characters +# to display on a single line. If the actual line length exceeds this threshold +# significantly it will wrapped across multiple lines. Some heuristics are apply +# to avoid ugly line breaks. +# Minimum value: 0, maximum value: 1000, default value: 17. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_WRAP_THRESHOLD = 17 + # If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and # collaboration graphs will show the relations between templates and their # instances. @@ -2360,6 +2545,11 @@ DIAFILE_DIRS = PLANTUML_JAR_PATH = +# When using plantuml, the PLANTUML_CFG_FILE tag can be used to specify a +# configuration file for plantuml. + +PLANTUML_CFG_FILE = + # When using plantuml, the specified paths are searched for files specified by # the !include statement in a plantuml block. @@ -2418,9 +2608,11 @@ DOT_MULTI_TARGETS = NO GENERATE_LEGEND = YES -# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot +# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate # files that are used to generate the various graphs. +# +# Note: This setting is not only used for dot files but also for msc and +# plantuml temporary files. # The default value is: YES. -# This tag requires that the tag HAVE_DOT is set to YES. DOT_CLEANUP = YES diff --git a/Makefile.in b/Makefile.in index 3dfda33..d7ac091 100644 --- a/Makefile.in +++ b/Makefile.in @@ -348,6 +348,8 @@ infodir = @infodir@ install_sh = @install_sh@ libbpf_CFLAGS = @libbpf_CFLAGS@ libbpf_LIBS = @libbpf_LIBS@ +libdbus_CFLAGS = @libdbus_CFLAGS@ +libdbus_LIBS = @libdbus_LIBS@ libdir = @libdir@ libdnssec_SONAME = @libdnssec_SONAME@ libdnssec_SOVERSION = @libdnssec_SOVERSION@ @@ -359,8 +361,6 @@ libfstrm_CFLAGS = @libfstrm_CFLAGS@ libfstrm_LIBS = @libfstrm_LIBS@ libidn2_CFLAGS = @libidn2_CFLAGS@ libidn2_LIBS = @libidn2_LIBS@ -libidn_CFLAGS = @libidn_CFLAGS@ -libidn_LIBS = @libidn_LIBS@ libknot_SONAME = @libknot_SONAME@ libknot_SOVERSION = @libknot_SOVERSION@ libknot_VERSION_INFO = @libknot_VERSION_INFO@ @@ -378,7 +378,6 @@ libprotobuf_c_CFLAGS = @libprotobuf_c_CFLAGS@ libprotobuf_c_LIBS = @libprotobuf_c_LIBS@ liburcu_CFLAGS = @liburcu_CFLAGS@ liburcu_LIBS = @liburcu_LIBS@ -liburcu_PKGCONFIG = @liburcu_PKGCONFIG@ libxdp_CFLAGS = @libxdp_CFLAGS@ libxdp_LIBS = @libxdp_LIBS@ libzscanner_SONAME = @libzscanner_SONAME@ @@ -1,3 +1,75 @@ +Knot DNS 3.4.0 (2024-09-02) +=========================== + +Features: +--------- + - knotd: full DNS over TLS (DoT, RFC 7858) implementation (see 'DNS over TLS') + - knotd: bidirectional XFR over TLS (XoT) support with opportunistic, strict, + and mutual authentication profiles + - knotd: support for DDNS over QUIC and TLS + - knotd: DNSSEC validation requires the remaining RRSIG validity is longer than 'rrsig-refresh' + - knotd: new event for automatic DNSSEC revalidation + - knotd: if enabled DNSSEC signing, EDNS expire is adjusted to the earliest RRSIG expiration + - knotd: added support for libdbus as an alternative to systemd dbus + (see '--enable-dbus=libdbus' configure parameter) + - knotd: new XDP-related configuration options + (see 'xdp.ring-size', 'xdp.busypoll-budget', and 'xdp.busypoll-timeout') + - knotc: new command for explicit triggering DNSSEC validation (see 'zone-validate' command) + - keymgr: SKR verification requires end of DNSKEY RRSIG validity covers next DNSKEY snapshot + - kdig: +nocrypto applies also to CERT, DS, SSHFP, DHCID, TLSA, ZONEMD, and TSIG + - knsupdate: added support for DDNS over QUIC and TLS (see '-Q' and '-S' parameters) + - kxdpgun: support for reading a binary input file (see '-B' parameter) + - kxdpgun: support for output in JSON (see '-j' parameter) + - kxdpgun: support for periodical output (see '-S' parameter) + - mod-rrl: module offers limiting of non-UDP protocols based on consumed time + (see 'mod-rrl.time-rate-limit' and 'mod-rrl.time-instant-limit') + - utils: -VV option for listing compile time configuration summary + +Improvements: +------------- + - knotd: up to eight DDNS queries can be queued per zone when frozen + - knotd: the number of created/validated RRSIGs is logged + - knotd: overhaul of atomic operations usage + - knotd: unified DNAME semantic errors with the CNAME ones + (see 'Handling CNAME and DNAME-related updates') + - knotd: better DDNS pre-check to prevent dropping a bulk of updates + - knotd: extended SOA presence semantic checks + - knotd: disallowed concurrent control zone and config transactions to avoid deadlock + - knotd: disallowed opening zone transaction when blocking command is running to avoid deadlock + - knotd: new XDP statistic counters + - knotd: remote zone serial is logged upon received incoming transfer + - knotd: zone backup stores and zone restore checks the CPU architecture compatibility + - knotd: time configuration options support 'w', 'M', and 'y' units + - knotd: some control commands can be processed asynchronously + - knotc: zone backup overwrites already existing backupdir in the force mode + - kdig: EDNS is enabled by default + - kdig: the default EDNS payload size was lowered to 1232 + - mod-rrl: completely reimplemented UDP rate limiting using an efficient + query-counting mechanism on several address prefix lengths + - mod-rrl: module no longer requires explicit configuration + - libknot: various XDP improvements and new configuration parameters + - docker: increased -D_FORTIFY_SOURCE to 3 + +Bugfixes: +--------- + - knotd: deadlock during zone-ksk-submitted processing of a frozen zone + - kxdpgun: race condition in SIGUSR1 signal processing + - doc: parallel build is unreliable #928 + +Compatibility: +-------------- + - configure: increase minimal GnuTLS version to 3.6.10 + - configure: removed deprecated libidn 1 support + - configure: removed liburcu search fallback + - configure: required GCC or LLVM Clang compiler with C11 support + - knotd: removed already ignored obsolete configuration options + - keymgr: removed legacy parameter '--brief' + - kjournalprint: removed legacy parameter '--no-color' + - kjournalprint: removed legacy database specification without '--dir' + - kcatalogprint: removed legacy database specification without '--dir' + - packaging: CentOS 7, Debian 10, and Ubuntu 18.04 no longer supported + - doc: removed info pages + Knot DNS 3.3.9 (2024-08-26) =========================== @@ -296,6 +368,76 @@ Packaging: - debian,ubuntu: new self-hosted repository (see https://pkg.labs.nic.cz/doc/) - docker: upgraded to Debian bookworm-slim +Knot DNS 3.2.13 (2024-06-25) +============================ + +Bugfixes: +--------- + - knotd: insufficient metadata check can cause journal corruption + - knotd: failed to build on macOS #909 + - knotd: early NSEC3 salt replanning if 'nsec3-salt-lifetime: -1' + - knotc: zone check complains about missing zone file #913 + - kdig: failed to parse empty QNAME (do not fill question section) + - python: failed to set an empty configuration value + - libzscanner: incorrect alpn processing #923 + - libknot: insufficient check for malformed TCP header options over XDP + - libknot: infinite loop in knot_rrset_to_wire_extra() #916 + +Knot DNS 3.2.12 (2023-12-19) +============================ + +Improvements: +------------- + - knotd: zone purging waits for finished zone expiration for better reliability + - doc: various fixes and extensions + +Bugfixes: +--------- + - knotd: zone backup fails due to improper backup context deinitialization #891 + - knotd: failed to sign the zone if maximum zone's TTL is too high + - knotd: malformed TCP header if used with QUIC in the generic XDP mode + - knotd: incorrect initialization of TCP limits + - knotd: orphaned PEM file not deleted when key generation fails + - knotd: server can crash when processing new TCP connections over XDP + - kdig: crashed when querying DNS over TLS if TLS handshake times out #896 + - kzonecheck: failed to check DS with SHA-1 or GOST if not supported by local policy + +Knot DNS 3.2.11 (2023-10-30) +============================ + +Improvements: +------------- + - keymgr: improved error message if a key file is not accessible + - keymgr: added offline RRSIGs validation at the end of their validity intervals + - doc: fixed some typos + +Bugfixes: +--------- + - knotd: DNAME record returned with query domain name instead of actual name #873 + - knotd: failed to import configuration file if mod-geoip is in use #881 + - knotd: failed to sign RRSet that fits to 64k only if compressed + - keymgr: offline RRSIGs not refreshed if 'rrsig-refresh' is not set + - knsupdate: incorrect processing of @ in the delete operation #879 + +Knot DNS 3.2.10 (2023-09-11) +============================ + +Improvements: +------------- + - knotd: multiple catalog groups per member are tolerated, but only one is used + - knotd: server cleans up stale LMDB readers when opening a RW transaction + +Bugfixes: +--------- + - knotd: server can crash when adjusting a wildcard glue + - knotd: failed to forward DDNS if 'zone.master' points to 'remotes' + - knotd: subsequent addition and removal to catalog zone isn't handled properly + - knotd: server can crash if a shared module is loaded and dynamic configuration used + - knotc: configuration import fails if an explicit shared module is configured + - kdig: double-free on some malformed responses over QUIC #869 + - kdig: some TLS parameters override QUIC parameters + - libs: NULL record with empty RDATA isn't allowed + Knot DNS 3.2.9 (2023-07-27) =========================== @@ -1,6 +1,5 @@ [![Coverity Status](https://img.shields.io/coverity/scan/knot-dns.svg)](https://scan.coverity.com/projects/knot-dns) [![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/knot-dns.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:knot-dns) -[![Documentation Status](https://readthedocs.org/projects/knot/badge/?version=master)](https://knot.readthedocs.io/en/master/) # Requirements @@ -29,7 +28,7 @@ sudo apt-get install \ #### Install optional packages: ```bash sudo apt-get install \ - libcap-ng-dev libsystemd-dev libidn2-0-dev libprotobuf-c-dev protobuf-c-compiler libfstrm-dev libmaxminddb-dev libnghttp2-dev libbpf-dev libxdp-dev libmnl-dev python3-sphinx python3-sphinx-panels + libcap-ng-dev libsystemd-dev libidn2-dev libprotobuf-c-dev protobuf-c-compiler libfstrm-dev libmaxminddb-dev libnghttp2-dev libbpf-dev libxdp-dev libmnl-dev python3-sphinx python3-sphinx-panels ``` ### Fedora like distributions @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.71 for knot 3.3.9. +# Generated by GNU Autoconf 2.71 for knot 3.4.0. # # Report bugs to <knot-dns@labs.nic.cz>. # @@ -621,8 +621,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='knot' PACKAGE_TARNAME='knot' -PACKAGE_VERSION='3.3.9' -PACKAGE_STRING='knot 3.3.9' +PACKAGE_VERSION='3.4.0' +PACKAGE_STRING='knot 3.4.0' PACKAGE_BUGREPORT='knot-dns@labs.nic.cz' PACKAGE_URL='' @@ -663,14 +663,6 @@ ac_subst_vars='am__EXEEXT_FALSE am__EXEEXT_TRUE LTLIBOBJS LIBOBJS -HAVE_MAKEINFO_FALSE -HAVE_MAKEINFO_TRUE -HAVE_PDFLATEX_FALSE -HAVE_PDFLATEX_TRUE -HAVE_SPHINXBUILD_FALSE -HAVE_SPHINXBUILD_TRUE -PDFLATEX -SPHINXBUILD OSS_FUZZ_FALSE OSS_FUZZ_TRUE FUZZER_FALSE @@ -695,8 +687,6 @@ libmnl_LIBS libmnl_CFLAGS libnghttp2_LIBS libnghttp2_CFLAGS -libidn_LIBS -libidn_CFLAGS libidn2_LIBS libidn2_CFLAGS embedded_libngtcp2_LIBS @@ -782,12 +772,13 @@ SHARED_MODULE_authsignal_FALSE SHARED_MODULE_authsignal_TRUE STATIC_MODULE_authsignal_FALSE STATIC_MODULE_authsignal_TRUE -liburcu_PKGCONFIG liburcu_LIBS liburcu_CFLAGS malloc_LIBS libkqueue_LIBS libkqueue_CFLAGS +libdbus_LIBS +libdbus_CFLAGS systemd_LIBS systemd_CFLAGS libxdp_LIBS @@ -802,10 +793,14 @@ gnutls_LIBS gnutls_CFLAGS FAST_PARSER_FALSE FAST_PARSER_TRUE -HAVE_LIBUTILS_FALSE -HAVE_LIBUTILS_TRUE +HAVE_PDFLATEX_FALSE +HAVE_PDFLATEX_TRUE HAVE_DOCS_FALSE HAVE_DOCS_TRUE +PDFLATEX +SPHINXBUILD +HAVE_LIBUTILS_FALSE +HAVE_LIBUTILS_TRUE HAVE_UTILS_FALSE HAVE_UTILS_TRUE HAVE_DAEMON_FALSE @@ -979,9 +974,9 @@ enable_recvmmsg enable_xdp enable_reuseport enable_systemd +enable_dbus with_socket_polling with_memory_allocator -with_urcu with_module_authsignal with_module_cookies with_module_dnsproxy @@ -1029,6 +1024,8 @@ libxdp_CFLAGS libxdp_LIBS systemd_CFLAGS systemd_LIBS +libdbus_CFLAGS +libdbus_LIBS libkqueue_CFLAGS libkqueue_LIBS liburcu_CFLAGS @@ -1047,8 +1044,6 @@ libngtcp2_CFLAGS libngtcp2_LIBS libidn2_CFLAGS libidn2_LIBS -libidn_CFLAGS -libidn_LIBS libnghttp2_CFLAGS libnghttp2_LIBS libmnl_CFLAGS @@ -1603,7 +1598,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures knot 3.3.9 to adapt to many kinds of systems. +\`configure' configures knot 3.4.0 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1674,7 +1669,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of knot 3.3.9:";; + short | recursive ) echo "Configuration of knot 3.4.0:";; esac cat <<\_ACEOF @@ -1706,6 +1701,8 @@ Optional Features: enable SO_REUSEPORT(_LB) support [default=auto] --enable-systemd=auto|yes|no enable systemd integration [default=auto] + --enable-dbus=auto|systemd|libdbus|no + enable D-bus support [default=auto] --enable-dnstap Enable dnstap support for kdig (requires fstrm, protobuf-c) --enable-maxminddb=auto|yes|no @@ -1742,7 +1739,6 @@ Optional Packages: --with-memory-allocator=auto|LIBRARY Use specific memory allocator for the server (e.g. jemalloc) [default=auto] - --with-urcu=DIR where to find userspace-rcu library --with-module-authsignal=yes|shared|no Build 'authsignal' module [default="yes"] --with-module-cookies=yes|shared|no @@ -1773,7 +1769,7 @@ Optional Packages: --with-conf-mapsize=NUM Configuration DB mapsize in MiB [default=$conf_mapsize_default] - --with-libidn=DIR Support IDN (needs GNU libidn2 or libidn) + --with-libidn=DIR Support IDN (needs GNU libidn2) --with-libnghttp2=DIR Support DoH (needs libnghttp2) --with-sanitizer Compile with sanitizer [default=no] --with-fuzzer Compile with libfuzzer [default=no] @@ -1808,6 +1804,10 @@ Some influential environment variables: C compiler flags for systemd, overriding pkg-config systemd_LIBS linker flags for systemd, overriding pkg-config + libdbus_CFLAGS + C compiler flags for libdbus, overriding pkg-config + libdbus_LIBS + linker flags for libdbus, overriding pkg-config libkqueue_CFLAGS C compiler flags for libkqueue, overriding pkg-config libkqueue_LIBS @@ -1842,9 +1842,6 @@ Some influential environment variables: C compiler flags for libidn2, overriding pkg-config libidn2_LIBS linker flags for libidn2, overriding pkg-config - libidn_CFLAGS - C compiler flags for libidn, overriding pkg-config - libidn_LIBS linker flags for libidn, overriding pkg-config libnghttp2_CFLAGS C compiler flags for libnghttp2, overriding pkg-config libnghttp2_LIBS @@ -1923,7 +1920,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -knot configure 3.3.9 +knot configure 3.4.0 generated by GNU Autoconf 2.71 Copyright (C) 2021 Free Software Foundation, Inc. @@ -2274,7 +2271,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by knot $as_me 3.3.9, which was +It was created by knot $as_me 3.4.0, which was generated by GNU Autoconf 2.71. Invocation command line was $ $0$ac_configure_args_raw @@ -2865,7 +2862,6 @@ as_fn_append ac_header_c_list " unistd.h unistd_h HAVE_UNISTD_H" as_fn_append ac_header_c_list " wchar.h wchar_h HAVE_WCHAR_H" as_fn_append ac_header_c_list " minix/config.h minix_config_h HAVE_MINIX_CONFIG_H" as_fn_append ac_header_c_list " pthread_np.h pthread_np_h HAVE_PTHREAD_NP_H" -as_fn_append ac_header_c_list " stdatomic.h stdatomic_h HAVE_STDATOMIC_H" as_fn_append ac_header_c_list " sys/uio.h sys_uio_h HAVE_SYS_UIO_H" as_fn_append ac_header_c_list " bsd/string.h bsd_string_h HAVE_BSD_STRING_H" @@ -3549,7 +3545,7 @@ fi # Define the identity of the package. PACKAGE='knot' - VERSION='3.3.9' + VERSION='3.4.0' printf "%s\n" "#define PACKAGE \"$PACKAGE\"" >>confdefs.h @@ -5196,22 +5192,22 @@ case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac # Update library versions # https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html - libknot_VERSION_INFO="-version-info 14:0:0" + libknot_VERSION_INFO="-version-info 15:0:0" - libknot_SOVERSION="14" + libknot_SOVERSION="15" case $host_os in #( darwin*) : - libknot_SONAME="libknot.14.dylib" + libknot_SONAME="libknot.15.dylib" ;; #( cygwin*) : - libknot_SONAME="cygknot-14.dll" + libknot_SONAME="cygknot-15.dll" ;; #( msys*) : - libknot_SONAME="msys-knot-14.dll" + libknot_SONAME="msys-knot-15.dll" ;; #( *) : - libknot_SONAME="libknot.so.14" + libknot_SONAME="libknot.so.15" ;; #( *) : @@ -5267,17 +5263,9 @@ esac KNOT_VERSION_MAJOR=3 -KNOT_VERSION_MINOR=3 +KNOT_VERSION_MINOR=4 -KNOT_VERSION_PATCH=9 - - -# Store ./configure parameters and CFLAGS - -printf "%s\n" "#define CONFIGURE_PARAMS \"$*\"" >>confdefs.h - - -printf "%s\n" "#define CONFIGURE_CFLAGS \"$CFLAGS\"" >>confdefs.h +KNOT_VERSION_PATCH=0 ac_config_files="$ac_config_files src/libknot/version.h src/libdnssec/version.h src/libzscanner/version.h" @@ -15272,6 +15260,15 @@ else HAVE_UTILS_FALSE= fi + if test "$enable_utilities" != "no" -o \ + "$enable_daemon" != "no"; then + HAVE_LIBUTILS_TRUE= + HAVE_LIBUTILS_FALSE='#' +else + HAVE_LIBUTILS_TRUE='#' + HAVE_LIBUTILS_FALSE= +fi + # Build Knot DNS documentation # Check whether --enable-documentation was given. @@ -15282,6 +15279,110 @@ else $as_nop enable_documentation=yes fi +if test "$enable_documentation" = "yes" +then : + + # Extract the first word of "sphinx-build", so it can be a program name with args. +set dummy sphinx-build; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_SPHINXBUILD+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $SPHINXBUILD in + [\\/]* | ?:[\\/]*) + ac_cv_path_SPHINXBUILD="$SPHINXBUILD" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_SPHINXBUILD="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + test -z "$ac_cv_path_SPHINXBUILD" && ac_cv_path_SPHINXBUILD="false" + ;; +esac +fi +SPHINXBUILD=$ac_cv_path_SPHINXBUILD +if test -n "$SPHINXBUILD"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $SPHINXBUILD" >&5 +printf "%s\n" "$SPHINXBUILD" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + + if test "$SPHINXBUILD" = "false" +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: missing 'sphinx-build' executable for documentation generation" >&5 +printf "%s\n" "$as_me: WARNING: missing 'sphinx-build' executable for documentation generation" >&2;} + enable_documentation=no + +fi + # Extract the first word of "pdflatex", so it can be a program name with args. +set dummy pdflatex; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_PDFLATEX+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $PDFLATEX in + [\\/]* | ?:[\\/]*) + ac_cv_path_PDFLATEX="$PDFLATEX" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_PDFLATEX="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + test -z "$ac_cv_path_PDFLATEX" && ac_cv_path_PDFLATEX="false" + ;; +esac +fi +PDFLATEX=$ac_cv_path_PDFLATEX +if test -n "$PDFLATEX"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PDFLATEX" >&5 +printf "%s\n" "$PDFLATEX" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + + +fi if test "$enable_documentation" = "yes"; then HAVE_DOCS_TRUE= HAVE_DOCS_FALSE='#' @@ -15290,16 +15391,15 @@ else HAVE_DOCS_FALSE= fi - - if test "$enable_utilities" != "no" -o \ - "$enable_daemon" != "no"; then - HAVE_LIBUTILS_TRUE= - HAVE_LIBUTILS_FALSE='#' + if test "$PDFLATEX" != "false"; then + HAVE_PDFLATEX_TRUE= + HAVE_PDFLATEX_FALSE='#' else - HAVE_LIBUTILS_TRUE='#' - HAVE_LIBUTILS_FALSE= + HAVE_PDFLATEX_TRUE='#' + HAVE_PDFLATEX_FALSE= fi + ###################### # Generic dependencies ###################### @@ -15410,19 +15510,19 @@ esac pkg_failed=no -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for gnutls >= 3.3" >&5 -printf %s "checking for gnutls >= 3.3... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for gnutls >= 3.6.10" >&5 +printf %s "checking for gnutls >= 3.6.10... " >&6; } if test -n "$gnutls_CFLAGS"; then pkg_cv_gnutls_CFLAGS="$gnutls_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ - { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gnutls >= 3.3\""; } >&5 - ($PKG_CONFIG --exists --print-errors "gnutls >= 3.3") 2>&5 + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gnutls >= 3.6.10\""; } >&5 + ($PKG_CONFIG --exists --print-errors "gnutls >= 3.6.10") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then - pkg_cv_gnutls_CFLAGS=`$PKG_CONFIG --cflags "gnutls >= 3.3" 2>/dev/null` + pkg_cv_gnutls_CFLAGS=`$PKG_CONFIG --cflags "gnutls >= 3.6.10" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes @@ -15434,12 +15534,12 @@ if test -n "$gnutls_LIBS"; then pkg_cv_gnutls_LIBS="$gnutls_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ - { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gnutls >= 3.3\""; } >&5 - ($PKG_CONFIG --exists --print-errors "gnutls >= 3.3") 2>&5 + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gnutls >= 3.6.10\""; } >&5 + ($PKG_CONFIG --exists --print-errors "gnutls >= 3.6.10") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then - pkg_cv_gnutls_LIBS=`$PKG_CONFIG --libs "gnutls >= 3.3" 2>/dev/null` + pkg_cv_gnutls_LIBS=`$PKG_CONFIG --libs "gnutls >= 3.6.10" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes @@ -15460,14 +15560,14 @@ else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then - gnutls_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "gnutls >= 3.3" 2>&1` + gnutls_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "gnutls >= 3.6.10" 2>&1` else - gnutls_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "gnutls >= 3.3" 2>&1` + gnutls_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "gnutls >= 3.6.10" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$gnutls_PKG_ERRORS" >&5 - as_fn_error $? "Package requirements (gnutls >= 3.3) were not met: + as_fn_error $? "Package requirements (gnutls >= 3.6.10) were not met: $gnutls_PKG_ERRORS @@ -15518,18 +15618,6 @@ printf "%s\n" "#define ENABLE_PKCS11 1" >>confdefs.h fi - ac_fn_check_decl "$LINENO" "GNUTLS_PK_EDDSA_ED25519" "ac_cv_have_decl_GNUTLS_PK_EDDSA_ED25519" "#include <gnutls/gnutls.h> -" "$ac_c_undeclared_builtin_options" "CFLAGS" -if test "x$ac_cv_have_decl_GNUTLS_PK_EDDSA_ED25519" = xyes -then : - -printf "%s\n" "#define HAVE_ED25519 1" >>confdefs.h - - enable_ed25519=yes -else $as_nop - enable_ed25519=no -fi - ac_fn_check_decl "$LINENO" "GNUTLS_SIGN_EDDSA_ED448" "ac_cv_have_decl_GNUTLS_SIGN_EDDSA_ED448" "#include <gnutls/gnutls.h> " "$ac_c_undeclared_builtin_options" "CFLAGS" if test "x$ac_cv_have_decl_GNUTLS_SIGN_EDDSA_ED448" = xyes @@ -15542,56 +15630,6 @@ else $as_nop enable_ed448=no fi - ac_fn_check_decl "$LINENO" "GNUTLS_PRIVKEY_FLAG_REPRODUCIBLE" "ac_cv_have_decl_GNUTLS_PRIVKEY_FLAG_REPRODUCIBLE" "#include <gnutls/abstract.h> -" "$ac_c_undeclared_builtin_options" "CFLAGS" -if test "x$ac_cv_have_decl_GNUTLS_PRIVKEY_FLAG_REPRODUCIBLE" = xyes -then : - -printf "%s\n" "#define HAVE_GNUTLS_REPRODUCIBLE 1" >>confdefs.h - - # Ensure the version is at least 3.6.10 - ac_fn_c_check_func "$LINENO" "gnutls_aead_cipher_encryptv2" "ac_cv_func_gnutls_aead_cipher_encryptv2" -if test "x$ac_cv_func_gnutls_aead_cipher_encryptv2" = xyes -then : - enable_repro_signing=yes -else $as_nop - enable_repro_signing=no -fi - -else $as_nop - enable_repro_signing=no -fi - - ac_fn_c_check_func "$LINENO" "gnutls_privkey_sign_data2" "ac_cv_func_gnutls_privkey_sign_data2" -if test "x$ac_cv_func_gnutls_privkey_sign_data2" = xyes -then : - -printf "%s\n" "#define HAVE_SIGN_DATA2 1" >>confdefs.h - -fi - - - ac_fn_c_check_func "$LINENO" "gnutls_privkey_export_x509" "ac_cv_func_gnutls_privkey_export_x509" -if test "x$ac_cv_func_gnutls_privkey_export_x509" = xyes -then : - -printf "%s\n" "#define HAVE_EXPORT_X509 1" >>confdefs.h - -fi - - - ac_fn_c_check_func "$LINENO" "gnutls_memset" "ac_cv_func_gnutls_memset" -if test "x$ac_cv_func_gnutls_memset" = xyes -then : - -printf "%s\n" "#define HAVE_GNUTLS_MEMSET 1" >>confdefs.h - - gnutls_memset=yes -else $as_nop - gnutls_memset=no -fi - - ac_fn_c_check_func "$LINENO" "gnutls_early_cipher_get" "ac_cv_func_gnutls_early_cipher_get" if test "x$ac_cv_func_gnutls_early_cipher_get" = xyes then : @@ -15972,6 +16010,15 @@ else $as_nop fi +# Check whether --enable-dbus was given. +if test ${enable_dbus+y} +then : + enableval=$enable_dbus; enable_dbus="$enableval" +else $as_nop + enable_dbus=auto +fi + + if test "$enable_daemon" = "yes" then : @@ -16462,16 +16509,187 @@ then : printf "%s\n" "#define ENABLE_SYSTEMD 1" >>confdefs.h - ac_fn_c_check_header_compile "$LINENO" "systemd/sd-bus.h" "ac_cv_header_systemd_sd_bus_h" "$ac_includes_default" -if test "x$ac_cv_header_systemd_sd_bus_h" = xyes +fi + +if test "$enable_dbus" != "no" +then : + + case $enable_dbus in #( + auto) : + if test "$enable_systemd" = "yes" +then : + +printf "%s\n" "#define ENABLE_DBUS_SYSTEMD 1" >>confdefs.h + + enable_dbus=systemd +else $as_nop + +pkg_failed=no +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dbus-1" >&5 +printf %s "checking for dbus-1... " >&6; } + +if test -n "$libdbus_CFLAGS"; then + pkg_cv_libdbus_CFLAGS="$libdbus_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"dbus-1\""; } >&5 + ($PKG_CONFIG --exists --print-errors "dbus-1") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_libdbus_CFLAGS=`$PKG_CONFIG --cflags "dbus-1" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$libdbus_LIBS"; then + pkg_cv_libdbus_LIBS="$libdbus_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"dbus-1\""; } >&5 + ($PKG_CONFIG --exists --print-errors "dbus-1") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_libdbus_LIBS=`$PKG_CONFIG --libs "dbus-1" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + libdbus_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "dbus-1" 2>&1` + else + libdbus_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "dbus-1" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$libdbus_PKG_ERRORS" >&5 + + enable_dbus=no +elif test $pkg_failed = untried; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + enable_dbus=no +else + libdbus_CFLAGS=$pkg_cv_libdbus_CFLAGS + libdbus_LIBS=$pkg_cv_libdbus_LIBS + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define ENABLE_DBUS_LIBDBUS 1" >>confdefs.h + + enable_dbus=libdbus +fi +fi ;; #( + systemd) : + if test "$enable_systemd" = "yes" then : -printf "%s\n" "#define ENABLE_DBUS 1" >>confdefs.h +printf "%s\n" "#define ENABLE_DBUS_SYSTEMD 1" >>confdefs.h + enable_dbus=systemd else $as_nop - enable_systemd="yes (without D-Bus)" + as_fn_error $? "systemd >= 221 not available." "$LINENO" 5 +fi ;; #( + libdbus) : + +pkg_failed=no +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dbus-1" >&5 +printf %s "checking for dbus-1... " >&6; } + +if test -n "$libdbus_CFLAGS"; then + pkg_cv_libdbus_CFLAGS="$libdbus_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"dbus-1\""; } >&5 + ($PKG_CONFIG --exists --print-errors "dbus-1") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_libdbus_CFLAGS=`$PKG_CONFIG --cflags "dbus-1" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$libdbus_LIBS"; then + pkg_cv_libdbus_LIBS="$libdbus_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"dbus-1\""; } >&5 + ($PKG_CONFIG --exists --print-errors "dbus-1") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_libdbus_LIBS=`$PKG_CONFIG --libs "dbus-1" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no fi + if test $_pkg_short_errors_supported = yes; then + libdbus_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "dbus-1" 2>&1` + else + libdbus_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "dbus-1" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$libdbus_PKG_ERRORS" >&5 + + as_fn_error $? "libdbus not available." "$LINENO" 5 +elif test $pkg_failed = untried; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + as_fn_error $? "libdbus not available." "$LINENO" 5 +else + libdbus_CFLAGS=$pkg_cv_libdbus_CFLAGS + libdbus_LIBS=$pkg_cv_libdbus_LIBS + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } +printf "%s\n" "#define ENABLE_DBUS_LIBDBUS 1" >>confdefs.h + + enable_dbus=libdbus +fi ;; #( + no) : + enable_dbus=no ;; #( + *) : + as_fn_error $? "Invalid value of --enable-dbus." "$LINENO" 5 ;; #( + *) : + ;; +esac fi @@ -16666,21 +16884,10 @@ then : fi - -# Check whether --with-urcu was given. -if test ${with_urcu+y} -then : - withval=$with_urcu; -fi - - if test "$enable_daemon" = "yes" then : -if test "$with_urcu" != "no" -then : - pkg_failed=no { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for liburcu" >&5 @@ -16741,217 +16948,13 @@ fi echo "$liburcu_PKG_ERRORS" >&5 - for try_urcu in "$with_urcu" "" "/usr/local"; do - save_LIBS="$LIBS" - save_CPPFLAGS="$CPPFLAGS" - - if test -d "$try_urcu" -then : - - liburcu_CFLAGS="-I$try_urcu/include" - liburcu_LIBS="-L$try_urcu/lib" - -else $as_nop - - liburcu_CFLAGS="" - liburcu_LIBS="" - -fi - - CPPFLAGS="$CPPFLAGS $liburcu_CFLAGS" - LIBS="$LIBS $liburcu_LIBS" - - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing rcu_set_pointer_sym" >&5 -printf %s "checking for library containing rcu_set_pointer_sym... " >&6; } -if test ${ac_cv_search_rcu_set_pointer_sym+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_func_search_save_LIBS=$LIBS -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char rcu_set_pointer_sym (); -int -main (void) -{ -return rcu_set_pointer_sym (); - ; - return 0; -} -_ACEOF -for ac_lib in '' urcu -do - if test -z "$ac_lib"; then - ac_res="none required" - else - ac_res=-l$ac_lib - LIBS="-l$ac_lib $ac_func_search_save_LIBS" - fi - if ac_fn_c_try_link "$LINENO" -then : - ac_cv_search_rcu_set_pointer_sym=$ac_res -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext - if test ${ac_cv_search_rcu_set_pointer_sym+y} -then : - break -fi -done -if test ${ac_cv_search_rcu_set_pointer_sym+y} -then : - -else $as_nop - ac_cv_search_rcu_set_pointer_sym=no -fi -rm conftest.$ac_ext -LIBS=$ac_func_search_save_LIBS -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_rcu_set_pointer_sym" >&5 -printf "%s\n" "$ac_cv_search_rcu_set_pointer_sym" >&6; } -ac_res=$ac_cv_search_rcu_set_pointer_sym -if test "$ac_res" != no -then : - test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" - - with_urcu=yes - liburcu_LIBS="$liburcu_LIBS -lurcu" - - - break - -else $as_nop - - CPPFLAGS="$save_CPPFLAGS" - LIBS="$save_LIBS" - with_urcu=no - # do not cache result of AC_SEARCH_LIBS test - unset ac_cv_search_rcu_set_pointer_sym - -fi - - done - CPPFLAGS="$save_CPPFLAGS" - LIBS="$save_LIBS" - - if test "$with_urcu" = "no" -then : - - as_fn_error $? "liburcu is required" "$LINENO" 5 - -fi + as_fn_error $? "liburcu not found" "$LINENO" 5 elif test $pkg_failed = untried; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } - for try_urcu in "$with_urcu" "" "/usr/local"; do - save_LIBS="$LIBS" - save_CPPFLAGS="$CPPFLAGS" - - if test -d "$try_urcu" -then : - - liburcu_CFLAGS="-I$try_urcu/include" - liburcu_LIBS="-L$try_urcu/lib" - -else $as_nop - - liburcu_CFLAGS="" - liburcu_LIBS="" - -fi - - CPPFLAGS="$CPPFLAGS $liburcu_CFLAGS" - LIBS="$LIBS $liburcu_LIBS" - - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing rcu_set_pointer_sym" >&5 -printf %s "checking for library containing rcu_set_pointer_sym... " >&6; } -if test ${ac_cv_search_rcu_set_pointer_sym+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_func_search_save_LIBS=$LIBS -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char rcu_set_pointer_sym (); -int -main (void) -{ -return rcu_set_pointer_sym (); - ; - return 0; -} -_ACEOF -for ac_lib in '' urcu -do - if test -z "$ac_lib"; then - ac_res="none required" - else - ac_res=-l$ac_lib - LIBS="-l$ac_lib $ac_func_search_save_LIBS" - fi - if ac_fn_c_try_link "$LINENO" -then : - ac_cv_search_rcu_set_pointer_sym=$ac_res -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext - if test ${ac_cv_search_rcu_set_pointer_sym+y} -then : - break -fi -done -if test ${ac_cv_search_rcu_set_pointer_sym+y} -then : - -else $as_nop - ac_cv_search_rcu_set_pointer_sym=no -fi -rm conftest.$ac_ext -LIBS=$ac_func_search_save_LIBS -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_rcu_set_pointer_sym" >&5 -printf "%s\n" "$ac_cv_search_rcu_set_pointer_sym" >&6; } -ac_res=$ac_cv_search_rcu_set_pointer_sym -if test "$ac_res" != no -then : - test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" - - with_urcu=yes - liburcu_LIBS="$liburcu_LIBS -lurcu" - - - break - -else $as_nop - - CPPFLAGS="$save_CPPFLAGS" - LIBS="$save_LIBS" - with_urcu=no - # do not cache result of AC_SEARCH_LIBS test - unset ac_cv_search_rcu_set_pointer_sym - -fi - - done - CPPFLAGS="$save_CPPFLAGS" - LIBS="$save_LIBS" - - if test "$with_urcu" = "no" -then : - - as_fn_error $? "liburcu is required" "$LINENO" 5 - -fi + as_fn_error $? "liburcu not found" "$LINENO" 5 else liburcu_CFLAGS=$pkg_cv_liburcu_CFLAGS @@ -16959,12 +16962,6 @@ else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } - liburcu_PKGCONFIG="liburcu >= 0.4.0" - - with_urcu=yes - -fi - fi @@ -19226,185 +19223,17 @@ fi echo "$libidn2_PKG_ERRORS" >&5 - -pkg_failed=no -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libidn >= 0.0.0" >&5 -printf %s "checking for libidn >= 0.0.0... " >&6; } - -if test -n "$libidn_CFLAGS"; then - pkg_cv_libidn_CFLAGS="$libidn_CFLAGS" - elif test -n "$PKG_CONFIG"; then - if test -n "$PKG_CONFIG" && \ - { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libidn >= 0.0.0\""; } >&5 - ($PKG_CONFIG --exists --print-errors "libidn >= 0.0.0") 2>&5 - ac_status=$? - printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then - pkg_cv_libidn_CFLAGS=`$PKG_CONFIG --cflags "libidn >= 0.0.0" 2>/dev/null` - test "x$?" != "x0" && pkg_failed=yes -else - pkg_failed=yes -fi - else - pkg_failed=untried -fi -if test -n "$libidn_LIBS"; then - pkg_cv_libidn_LIBS="$libidn_LIBS" - elif test -n "$PKG_CONFIG"; then - if test -n "$PKG_CONFIG" && \ - { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libidn >= 0.0.0\""; } >&5 - ($PKG_CONFIG --exists --print-errors "libidn >= 0.0.0") 2>&5 - ac_status=$? - printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then - pkg_cv_libidn_LIBS=`$PKG_CONFIG --libs "libidn >= 0.0.0" 2>/dev/null` - test "x$?" != "x0" && pkg_failed=yes -else - pkg_failed=yes -fi - else - pkg_failed=untried -fi - - - -if test $pkg_failed = yes; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } - -if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then - _pkg_short_errors_supported=yes -else - _pkg_short_errors_supported=no -fi - if test $_pkg_short_errors_supported = yes; then - libidn_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libidn >= 0.0.0" 2>&1` - else - libidn_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libidn >= 0.0.0" 2>&1` - fi - # Put the nasty error message in config.log where it belongs - echo "$libidn_PKG_ERRORS" >&5 - - - with_libidn=no - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: libidn2 or libidn not found" >&5 -printf "%s\n" "$as_me: WARNING: libidn2 or libidn not found" >&2;} - -elif test $pkg_failed = untried; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } - - with_libidn=no - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: libidn2 or libidn not found" >&5 -printf "%s\n" "$as_me: WARNING: libidn2 or libidn not found" >&2;} - -else - libidn_CFLAGS=$pkg_cv_libidn_CFLAGS - libidn_LIBS=$pkg_cv_libidn_LIBS - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf "%s\n" "yes" >&6; } - - with_libidn=libidn - -printf "%s\n" "#define LIBIDN 1" >>confdefs.h - - -printf "%s\n" "#define LIBIDN_HEADER <idna.h>" >>confdefs.h - - -fi - -elif test $pkg_failed = untried; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } - - -pkg_failed=no -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libidn >= 0.0.0" >&5 -printf %s "checking for libidn >= 0.0.0... " >&6; } - -if test -n "$libidn_CFLAGS"; then - pkg_cv_libidn_CFLAGS="$libidn_CFLAGS" - elif test -n "$PKG_CONFIG"; then - if test -n "$PKG_CONFIG" && \ - { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libidn >= 0.0.0\""; } >&5 - ($PKG_CONFIG --exists --print-errors "libidn >= 0.0.0") 2>&5 - ac_status=$? - printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then - pkg_cv_libidn_CFLAGS=`$PKG_CONFIG --cflags "libidn >= 0.0.0" 2>/dev/null` - test "x$?" != "x0" && pkg_failed=yes -else - pkg_failed=yes -fi - else - pkg_failed=untried -fi -if test -n "$libidn_LIBS"; then - pkg_cv_libidn_LIBS="$libidn_LIBS" - elif test -n "$PKG_CONFIG"; then - if test -n "$PKG_CONFIG" && \ - { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libidn >= 0.0.0\""; } >&5 - ($PKG_CONFIG --exists --print-errors "libidn >= 0.0.0") 2>&5 - ac_status=$? - printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then - pkg_cv_libidn_LIBS=`$PKG_CONFIG --libs "libidn >= 0.0.0" 2>/dev/null` - test "x$?" != "x0" && pkg_failed=yes -else - pkg_failed=yes -fi - else - pkg_failed=untried -fi - - - -if test $pkg_failed = yes; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } - -if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then - _pkg_short_errors_supported=yes -else - _pkg_short_errors_supported=no -fi - if test $_pkg_short_errors_supported = yes; then - libidn_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libidn >= 0.0.0" 2>&1` - else - libidn_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libidn >= 0.0.0" 2>&1` - fi - # Put the nasty error message in config.log where it belongs - echo "$libidn_PKG_ERRORS" >&5 - - - with_libidn=no - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: libidn2 or libidn not found" >&5 -printf "%s\n" "$as_me: WARNING: libidn2 or libidn not found" >&2;} + with_libidn=no + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: libidn2 not found" >&5 +printf "%s\n" "$as_me: WARNING: libidn2 not found" >&2;} elif test $pkg_failed = untried; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } - with_libidn=no - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: libidn2 or libidn not found" >&5 -printf "%s\n" "$as_me: WARNING: libidn2 or libidn not found" >&2;} - -else - libidn_CFLAGS=$pkg_cv_libidn_CFLAGS - libidn_LIBS=$pkg_cv_libidn_LIBS - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf "%s\n" "yes" >&6; } - - with_libidn=libidn - -printf "%s\n" "#define LIBIDN 1" >>confdefs.h - - -printf "%s\n" "#define LIBIDN_HEADER <idna.h>" >>confdefs.h - - -fi + with_libidn=no + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: libidn2 not found" >&5 +printf "%s\n" "$as_me: WARNING: libidn2 not found" >&2;} else libidn2_CFLAGS=$pkg_cv_libidn2_CFLAGS @@ -19417,9 +19246,6 @@ printf "%s\n" "yes" >&6; } printf "%s\n" "#define LIBIDN 1" >>confdefs.h -printf "%s\n" "#define LIBIDN_HEADER <idn2.h>" >>confdefs.h - - fi fi @@ -20245,7 +20071,6 @@ fi - # Checks for optional library functions. ac_fn_c_check_func "$LINENO" "accept4" "ac_cv_func_accept4" if test "x$ac_cv_func_accept4" = xyes @@ -20330,7 +20155,7 @@ else $as_nop fi - if test "$explicit_bzero" = "no" -a "$explicit_memset" = "no" -a "$gnutls_memset" = "yes"; then + if test "$explicit_bzero" = "no" -a "$explicit_memset" = "no"; then USE_GNUTLS_MEMSET_TRUE= USE_GNUTLS_MEMSET_FALSE='#' else @@ -20409,14 +20234,19 @@ fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext -# Check for '__atomic' compiler builtin atomic functions. +# Check for a C11 or GCC-style '__atomic' compiler builtin atomic functions. +atomic_type="none" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ -#include <stdint.h> +#if (__STDC_VERSION__ < 201112L) || defined(__STDC_NO_ATOMICS__) + #error "No C11 atomics" + #endif + #include <stdatomic.h> int main (void) { -uint64_t val = 0; __atomic_add_fetch(&val, 1, __ATOMIC_RELAXED); +atomic_uint_fast64_t val = 0; + atomic_fetch_add_explicit(&val, 1, memory_order_relaxed); ; return 0; } @@ -20424,21 +20254,17 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : -printf "%s\n" "#define HAVE_ATOMIC 1" >>confdefs.h - - -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext +printf "%s\n" "#define HAVE_C11_ATOMIC 1" >>confdefs.h -# Check for '__sync' compiler builtin atomic functions. -cat confdefs.h - <<_ACEOF >conftest.$ac_ext + atomic_type="C11" +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <stdint.h> int main (void) { -int val = 0; __sync_add_and_fetch(&val, 1); +uint64_t val = 0; __atomic_add_fetch(&val, 1, __ATOMIC_RELAXED); ; return 0; } @@ -20446,8 +20272,13 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : -printf "%s\n" "#define HAVE_SYNC_ATOMIC 1" >>confdefs.h +printf "%s\n" "#define HAVE_GCC_ATOMIC 1" >>confdefs.h + + atomic_type="__atomic" +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ @@ -20799,191 +20630,15 @@ else fi -if test "$enable_documentation" = "yes" -then : - - -# Extract the first word of "sphinx-build", so it can be a program name with args. -set dummy sphinx-build; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_path_SPHINXBUILD+y} -then : - printf %s "(cached) " >&6 -else $as_nop - case $SPHINXBUILD in - [\\/]* | ?:[\\/]*) - ac_cv_path_SPHINXBUILD="$SPHINXBUILD" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_path_SPHINXBUILD="$as_dir$ac_word$ac_exec_ext" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - - test -z "$ac_cv_path_SPHINXBUILD" && ac_cv_path_SPHINXBUILD="false" - ;; -esac -fi -SPHINXBUILD=$ac_cv_path_SPHINXBUILD -if test -n "$SPHINXBUILD"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $SPHINXBUILD" >&5 -printf "%s\n" "$SPHINXBUILD" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - -if test "$SPHINXBUILD" = "false" -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: missing 'sphinx-build' executable for documentation generation" >&5 -printf "%s\n" "$as_me: WARNING: missing 'sphinx-build' executable for documentation generation" >&2;} - -fi -# Extract the first word of "pdflatex", so it can be a program name with args. -set dummy pdflatex; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_path_PDFLATEX+y} -then : - printf %s "(cached) " >&6 -else $as_nop - case $PDFLATEX in - [\\/]* | ?:[\\/]*) - ac_cv_path_PDFLATEX="$PDFLATEX" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_path_PDFLATEX="$as_dir$ac_word$ac_exec_ext" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - - test -z "$ac_cv_path_PDFLATEX" && ac_cv_path_PDFLATEX="false" - ;; -esac -fi -PDFLATEX=$ac_cv_path_PDFLATEX -if test -n "$PDFLATEX"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PDFLATEX" >&5 -printf "%s\n" "$PDFLATEX" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - -# Extract the first word of "makeinfo", so it can be a program name with args. -set dummy makeinfo; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_path_MAKEINFO+y} -then : - printf %s "(cached) " >&6 -else $as_nop - case $MAKEINFO in - [\\/]* | ?:[\\/]*) - ac_cv_path_MAKEINFO="$MAKEINFO" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_path_MAKEINFO="$as_dir$ac_word$ac_exec_ext" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - - test -z "$ac_cv_path_MAKEINFO" && ac_cv_path_MAKEINFO="false" - ;; -esac -fi -MAKEINFO=$ac_cv_path_MAKEINFO -if test -n "$MAKEINFO"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MAKEINFO" >&5 -printf "%s\n" "$MAKEINFO" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - - - -fi - - if test "$SPHINXBUILD" != "false"; then - HAVE_SPHINXBUILD_TRUE= - HAVE_SPHINXBUILD_FALSE='#' -else - HAVE_SPHINXBUILD_TRUE='#' - HAVE_SPHINXBUILD_FALSE= -fi - - if test "$PDFLATEX" != "false"; then - HAVE_PDFLATEX_TRUE= - HAVE_PDFLATEX_FALSE='#' -else - HAVE_PDFLATEX_TRUE='#' - HAVE_PDFLATEX_FALSE= -fi - - if test "$MAKEINFO" != "false"; then - HAVE_MAKEINFO_TRUE= - HAVE_MAKEINFO_FALSE='#' -else - HAVE_MAKEINFO_TRUE='#' - HAVE_MAKEINFO_FALSE= -fi - - # Strip -fdebug-prefix-map= parameters from flags for better reproducibility of binaries. filtered_cflags=$(echo -n "$CFLAGS" | \ sed 's/[^[:alnum:]]-f[^[:space:]]*-prefix-map=[^[:space:]]*//g') filtered_cppflags=$(echo -n "$CPPFLAGS" | \ sed 's/[^[:alnum:]]-f[^[:space:]]*-prefix-map=[^[:space:]]*//g') +filtered_config_params=$(echo -n "$ac_configure_args" | \ + sed 's/[^[:alnum:]]-f[^[:space:]]*-prefix-map=[^[:space:]]*//g') -result_msg_base=" Knot DNS $VERSION - +result_msg_base=" Target: $host_os $host_cpu $endianity Compiler: ${CC} CFLAGS: ${filtered_cflags} ${filtered_cppflags} @@ -21013,6 +20668,7 @@ result_msg_base=" Knot DNS $VERSION XDP support: ${enable_xdp} DoQ support: ${enable_quic} Socket polling: ${socket_polling} + Atomic support: ${atomic_type} Memory allocator: ${with_memory_allocator} Fast zone parser: ${enable_fastparser} Utilities with IDN: ${with_libidn} @@ -21020,17 +20676,17 @@ result_msg_base=" Knot DNS $VERSION Utilities with Dnstap: ${enable_dnstap} MaxMind DB support: ${enable_maxminddb} Systemd integration: ${enable_systemd} + D-Bus support: ${enable_dbus} POSIX capabilities: ${enable_cap_ng} PKCS #11 support: ${enable_pkcs11} - Ed25519 support: ${enable_ed25519} Ed448 support: ${enable_ed448} - Reproducible signing: ${enable_repro_signing} + Code coverage: ${enable_code_coverage} Sanitizer: ${with_sanitizer} LibFuzzer: ${with_fuzzer} OSS-Fuzz: ${with_oss_fuzz}" -result_msg_esc=$(echo -n "$result_msg_base" | sed '$!s/$/\\n/' | tr -d '\n') +result_msg_esc=$(echo -n " Configure:$filtered_config_params\n$result_msg_base" | sed '$!s/$/\\n/' | tr -d '\n') printf "%s\n" "#define CONFIGURE_SUMMARY \"$result_msg_esc\"" >>confdefs.h @@ -21188,12 +20844,16 @@ if test -z "${HAVE_UTILS_TRUE}" && test -z "${HAVE_UTILS_FALSE}"; then as_fn_error $? "conditional \"HAVE_UTILS\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi +if test -z "${HAVE_LIBUTILS_TRUE}" && test -z "${HAVE_LIBUTILS_FALSE}"; then + as_fn_error $? "conditional \"HAVE_LIBUTILS\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi if test -z "${HAVE_DOCS_TRUE}" && test -z "${HAVE_DOCS_FALSE}"; then as_fn_error $? "conditional \"HAVE_DOCS\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi -if test -z "${HAVE_LIBUTILS_TRUE}" && test -z "${HAVE_LIBUTILS_FALSE}"; then - as_fn_error $? "conditional \"HAVE_LIBUTILS\" was never defined. +if test -z "${HAVE_PDFLATEX_TRUE}" && test -z "${HAVE_PDFLATEX_FALSE}"; then + as_fn_error $? "conditional \"HAVE_PDFLATEX\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${FAST_PARSER_TRUE}" && test -z "${FAST_PARSER_FALSE}"; then @@ -21348,18 +21008,6 @@ if test -z "${OSS_FUZZ_TRUE}" && test -z "${OSS_FUZZ_FALSE}"; then as_fn_error $? "conditional \"OSS_FUZZ\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi -if test -z "${HAVE_SPHINXBUILD_TRUE}" && test -z "${HAVE_SPHINXBUILD_FALSE}"; then - as_fn_error $? "conditional \"HAVE_SPHINXBUILD\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${HAVE_PDFLATEX_TRUE}" && test -z "${HAVE_PDFLATEX_FALSE}"; then - as_fn_error $? "conditional \"HAVE_PDFLATEX\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${HAVE_MAKEINFO_TRUE}" && test -z "${HAVE_MAKEINFO_FALSE}"; then - as_fn_error $? "conditional \"HAVE_MAKEINFO\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi : "${CONFIG_STATUS=./config.status}" ac_write_fail=0 @@ -21750,7 +21398,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by knot $as_me 3.3.9, which was +This file was extended by knot $as_me 3.4.0, which was generated by GNU Autoconf 2.71. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -21818,7 +21466,7 @@ ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config='$ac_cs_config_escaped' ac_cs_version="\\ -knot config.status 3.3.9 +knot config.status 3.4.0 configured by $0, generated by GNU Autoconf 2.71, with options \\"\$ac_cs_config\\" @@ -23543,9 +23191,11 @@ printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: + Knot DNS $VERSION $result_msg_base " >&5 printf "%s\n" " + Knot DNS $VERSION $result_msg_base " >&6; } diff --git a/configure.ac b/configure.ac index 5a7ef6f..eb11c14 100644 --- a/configure.ac +++ b/configure.ac @@ -1,8 +1,8 @@ AC_PREREQ([2.69]) m4_define([knot_VERSION_MAJOR], 3)dnl -m4_define([knot_VERSION_MINOR], 3)dnl -m4_define([knot_VERSION_PATCH], 9)dnl Leave empty if the master branch! +m4_define([knot_VERSION_MINOR], 4)dnl +m4_define([knot_VERSION_PATCH], 0)dnl Leave empty if the master branch! m4_include([m4/knot-version.m4]) AC_INIT([knot], [knot_PKG_VERSION], [knot-dns@labs.nic.cz]) @@ -16,7 +16,7 @@ AC_CANONICAL_HOST # Update library versions # https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html -KNOT_LIB_VERSION([libknot], 14, 0, 0) +KNOT_LIB_VERSION([libknot], 15, 0, 0) KNOT_LIB_VERSION([libdnssec], 9, 0, 0) KNOT_LIB_VERSION([libzscanner], 4, 0, 0) @@ -24,10 +24,6 @@ AC_SUBST([KNOT_VERSION_MAJOR], knot_VERSION_MAJOR) AC_SUBST([KNOT_VERSION_MINOR], knot_VERSION_MINOR) AC_SUBST([KNOT_VERSION_PATCH], knot_VERSION_PATCH) -# Store ./configure parameters and CFLAGS -AC_DEFINE_UNQUOTED([CONFIGURE_PARAMS],["$*"],[Params passed to configure]) -AC_DEFINE_UNQUOTED([CONFIGURE_CFLAGS],["$CFLAGS"],[Passed CFLAGS from environment]) - AC_CONFIG_FILES([src/libknot/version.h src/libdnssec/version.h src/libzscanner/version.h]) @@ -119,14 +115,23 @@ AC_ARG_ENABLE([modules], AC_ARG_ENABLE([utilities], AS_HELP_STRING([--disable-utilities], [Don't build Knot DNS utilities]), [], [enable_utilities=yes]) AM_CONDITIONAL([HAVE_UTILS], [test "$enable_utilities" = "yes"]) +AM_CONDITIONAL([HAVE_LIBUTILS], test "$enable_utilities" != "no" -o \ + "$enable_daemon" != "no") # Build Knot DNS documentation AC_ARG_ENABLE([documentation], AS_HELP_STRING([--disable-documentation], [Don't build Knot DNS documentation]), [], [enable_documentation=yes]) +AS_IF([test "$enable_documentation" = "yes"], [ + AC_PATH_PROG([SPHINXBUILD], [sphinx-build], [false]) + AS_IF([test "$SPHINXBUILD" = "false"], + [AC_MSG_WARN([missing 'sphinx-build' executable for documentation generation]) + enable_documentation=no] + ) + AC_PATH_PROG([PDFLATEX], [pdflatex], [false]) +]) AM_CONDITIONAL([HAVE_DOCS], [test "$enable_documentation" = "yes"]) +AM_CONDITIONAL([HAVE_PDFLATEX], test "$PDFLATEX" != "false") -AM_CONDITIONAL([HAVE_LIBUTILS], test "$enable_utilities" != "no" -o \ - "$enable_daemon" != "no") ###################### # Generic dependencies ###################### @@ -138,7 +143,7 @@ AC_ARG_ENABLE([fastparser], AM_CONDITIONAL([FAST_PARSER], [test "$enable_fastparser" = "yes"]) # GnuTLS crypto backend -PKG_CHECK_MODULES([gnutls], [gnutls >= 3.3], [ +PKG_CHECK_MODULES([gnutls], [gnutls >= 3.6.10], [ save_CFLAGS=$CFLAGS save_LIBS=$LIBS CFLAGS="$CFLAGS $gnutls_CFLAGS" @@ -148,35 +153,12 @@ PKG_CHECK_MODULES([gnutls], [gnutls >= 3.3], [ AS_IF([test "$enable_pkcs11" = yes], [AC_DEFINE([ENABLE_PKCS11], [1], [PKCS #11 support available])]) - AC_CHECK_DECL([GNUTLS_PK_EDDSA_ED25519], - [AC_DEFINE([HAVE_ED25519], [1], [GnuTLS ED25519 support available]) - enable_ed25519=yes], - [enable_ed25519=no], - [#include <gnutls/gnutls.h>]) - AC_CHECK_DECL([GNUTLS_SIGN_EDDSA_ED448], [AC_DEFINE([HAVE_ED448], [1], [GnuTLS ED448 support available]) enable_ed448=yes], [enable_ed448=no], [#include <gnutls/gnutls.h>]) - AC_CHECK_DECL([GNUTLS_PRIVKEY_FLAG_REPRODUCIBLE], - [AC_DEFINE([HAVE_GNUTLS_REPRODUCIBLE], [1], [GnuTLS reproducible signing available]) - # Ensure the version is at least 3.6.10 - AC_CHECK_FUNC([gnutls_aead_cipher_encryptv2], [enable_repro_signing=yes], [enable_repro_signing=no])], - [enable_repro_signing=no], - [#include <gnutls/abstract.h>]) - - AC_CHECK_FUNC([gnutls_privkey_sign_data2], - [AC_DEFINE([HAVE_SIGN_DATA2], [1], [gnutls_privkey_sign_data2 available])]) - - AC_CHECK_FUNC([gnutls_privkey_export_x509], - [AC_DEFINE([HAVE_EXPORT_X509], [1], [gnutls_privkey_export_x509 available])]) - - AC_CHECK_FUNC([gnutls_memset], - [AC_DEFINE([HAVE_GNUTLS_MEMSET], [1], [gnutls_memset available]) - gnutls_memset=yes], [gnutls_memset=no]) - AC_CHECK_FUNC([gnutls_early_cipher_get], [AC_DEFINE([HAVE_GNUTLS_QUIC], [1], [gnutls_early_cipher_get available]) gnutls_quic=yes], [gnutls_quic=no]) @@ -281,6 +263,10 @@ AC_ARG_ENABLE([systemd], AS_HELP_STRING([--enable-systemd=auto|yes|no], [enable systemd integration [default=auto]]), [enable_systemd="$enableval"], [enable_systemd=auto]) +AC_ARG_ENABLE([dbus], + AS_HELP_STRING([--enable-dbus=auto|systemd|libdbus|no], [enable D-bus support [default=auto]]), + [enable_dbus="$enableval"], [enable_dbus=auto]) + AS_IF([test "$enable_daemon" = "yes"],[ AS_IF([test "$enable_systemd" != "no"],[ @@ -293,11 +279,28 @@ AS_IF([test "$enable_systemd" != "no"],[ ]) AS_IF([test "$enable_systemd" = "yes"],[ - AC_DEFINE([ENABLE_SYSTEMD], [1], [Use systemd integration.]) - AC_CHECK_HEADER([systemd/sd-bus.h], - [AC_DEFINE([ENABLE_DBUS], [1], [systemd D-Bus available])], - [enable_systemd="yes (without D-Bus)"]) -]) + AC_DEFINE([ENABLE_SYSTEMD], [1], [Use systemd integration.])]) + +AS_IF([test "$enable_dbus" != "no"],[ + AS_CASE([$enable_dbus], + [auto],[AS_IF([test "$enable_systemd" = "yes"], + [AC_DEFINE([ENABLE_DBUS_SYSTEMD], [1], [systemd D-Bus available]) + enable_dbus=systemd], + [PKG_CHECK_MODULES([libdbus], [dbus-1], + [AC_DEFINE([ENABLE_DBUS_LIBDBUS], [1], [libdbus D-Bus available]) + enable_dbus=libdbus], + [enable_dbus=no])])], + [systemd],[AS_IF([test "$enable_systemd" = "yes"], + [AC_DEFINE([ENABLE_DBUS_SYSTEMD], [1], [systemd D-Bus available]) + enable_dbus=systemd], + [AC_MSG_ERROR([systemd >= 221 not available.])])], + [libdbus],[PKG_CHECK_MODULES([libdbus], [dbus-1], + [AC_DEFINE([ENABLE_DBUS_LIBDBUS], [1], [libdbus D-Bus available]) + enable_dbus=libdbus], + [AC_MSG_ERROR([libdbus not available.])])], + [no],[enable_dbus=no], + [*],[AC_MSG_ERROR([Invalid value of --enable-dbus.])]) + ]) ]) dnl enable_daemon @@ -347,54 +350,10 @@ AC_ARG_WITH([memory-allocator], AS_IF([test "$with_memory_allocator" = ""], [with_memory_allocator="auto"]) AC_SUBST([malloc_LIBS]) -dnl Check for userspace-rcu library -AC_ARG_WITH(urcu, -[ --with-urcu=DIR where to find userspace-rcu library]) - AS_IF([test "$enable_daemon" = "yes"],[ -AS_IF([test "$with_urcu" != "no"], [ - PKG_CHECK_MODULES([liburcu], liburcu, [ - liburcu_PKGCONFIG="liburcu >= 0.4.0" - AC_SUBST([liburcu_PKGCONFIG]) - with_urcu=yes - ],[ - for try_urcu in "$with_urcu" "" "/usr/local"; do - save_LIBS="$LIBS" - save_CPPFLAGS="$CPPFLAGS" - - AS_IF([test -d "$try_urcu"], [ - liburcu_CFLAGS="-I$try_urcu/include" - liburcu_LIBS="-L$try_urcu/lib" - ],[ - liburcu_CFLAGS="" - liburcu_LIBS="" - ]) - - CPPFLAGS="$CPPFLAGS $liburcu_CFLAGS" - LIBS="$LIBS $liburcu_LIBS" - - AC_SEARCH_LIBS([rcu_set_pointer_sym], [urcu], [ - with_urcu=yes - liburcu_LIBS="$liburcu_LIBS -lurcu" - AC_SUBST([liburcu_CFLAGS]) - AC_SUBST([liburcu_LIBS]) - break - ],[ - CPPFLAGS="$save_CPPFLAGS" - LIBS="$save_LIBS" - with_urcu=no - # do not cache result of AC_SEARCH_LIBS test - unset ac_cv_search_rcu_set_pointer_sym - ]) - done - CPPFLAGS="$save_CPPFLAGS" - LIBS="$save_LIBS" - - AS_IF([test "$with_urcu" = "no"],[ - AC_MSG_ERROR([liburcu is required]) - ]) - ]) +PKG_CHECK_MODULES([liburcu], [liburcu], [], [ + AC_MSG_ERROR([liburcu not found]) ]) ]) @@ -604,9 +563,9 @@ AS_IF([test "$enable_quic" != "no"], [ # Dependencies needed for Knot DNS utilities ############################################ -dnl Check for libidn. +dnl Check for libidn2. AC_ARG_WITH(libidn, - AS_HELP_STRING([--with-libidn=[DIR]], [Support IDN (needs GNU libidn2 or libidn)]), + AS_HELP_STRING([--with-libidn=[DIR]], [Support IDN (needs GNU libidn2)]), with_libidn=$withval, with_libidn=yes ) @@ -623,16 +582,9 @@ AS_IF([test "$enable_utilities" = "yes"], [ PKG_CHECK_MODULES([libidn2], [libidn2 >= 2.0.0], [ with_libidn=libidn2 AC_DEFINE([LIBIDN], [1], [Define to 1 to enable IDN support]) - AC_DEFINE([LIBIDN_HEADER], [<idn2.h>], [Define to proper libidn header]) ], [ - PKG_CHECK_MODULES([libidn], [libidn >= 0.0.0], [ - with_libidn=libidn - AC_DEFINE([LIBIDN], [1], [Define to 1 to enable IDN support]) - AC_DEFINE([LIBIDN_HEADER], [<idna.h>], [Define to proper libidn header]) - ], [ - with_libidn=no - AC_MSG_WARN([libidn2 or libidn not found]) - ]) + with_libidn=no + AC_MSG_WARN([libidn2 not found]) ]) ]) @@ -721,7 +673,7 @@ LIBS="$save_LIBS" # Checks for header files. AC_HEADER_RESOLV -AC_CHECK_HEADERS_ONCE([pthread_np.h stdatomic.h sys/uio.h bsd/string.h]) +AC_CHECK_HEADERS_ONCE([pthread_np.h sys/uio.h bsd/string.h]) # Checks for optional library functions. AC_CHECK_FUNCS([accept4 fgetln getline initgroups malloc_trim \ @@ -736,7 +688,7 @@ AC_CHECK_FUNC([explicit_memset], [ AC_DEFINE([HAVE_EXPLICIT_MEMSET], [1], [explicit_memset available]) explicit_memset=yes], [explicit_memset=no] ) -AM_CONDITIONAL([USE_GNUTLS_MEMSET], [test "$explicit_bzero" = "no" -a "$explicit_memset" = "no" -a "$gnutls_memset" = "yes"]) +AM_CONDITIONAL([USE_GNUTLS_MEMSET], [test "$explicit_bzero" = "no" -a "$explicit_memset" = "no"]) # Check for mandatory library functions. AC_CHECK_FUNC([vasprintf], [], [ @@ -750,18 +702,23 @@ AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <pthread_np.h>]], [[cpuset_t set; CPU AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <sched.h>]], [[cpuset_t* set = cpuset_create(); cpuset_destroy(set);]])], [AC_DEFINE(HAVE_CPUSET_NETBSD, 1, [Define if cpuset_t and cpuset(3) exists.])]) -# Check for '__atomic' compiler builtin atomic functions. -AC_LINK_IFELSE( - [AC_LANG_PROGRAM([[#include <stdint.h>]], - [[uint64_t val = 0; __atomic_add_fetch(&val, 1, __ATOMIC_RELAXED);]])], - [AC_DEFINE(HAVE_ATOMIC, 1, [Define to 1 if you have '__atomic' functions.])] -) - -# Check for '__sync' compiler builtin atomic functions. +# Check for a C11 or GCC-style '__atomic' compiler builtin atomic functions. +atomic_type="none" AC_LINK_IFELSE( - [AC_LANG_PROGRAM([[#include <stdint.h>]], - [[int val = 0; __sync_add_and_fetch(&val, 1);]])], - [AC_DEFINE(HAVE_SYNC_ATOMIC, 1, [Define to 1 if you have '__sync' functions.])] + [AC_LANG_PROGRAM([[#if (__STDC_VERSION__ < 201112L) || defined(__STDC_NO_ATOMICS__) + #error "No C11 atomics" + #endif + #include <stdatomic.h>]], + [[atomic_uint_fast64_t val = 0;]] + [[atomic_fetch_add_explicit(&val, 1, memory_order_relaxed);]])], + [AC_DEFINE(HAVE_C11_ATOMIC, 1, [Define to 1 if you have C11 'atomic' functions.]) + atomic_type="C11"], + AC_LINK_IFELSE( + [AC_LANG_PROGRAM([[#include <stdint.h>]], + [[uint64_t val = 0; __atomic_add_fetch(&val, 1, __ATOMIC_RELAXED);]])], + [AC_DEFINE(HAVE_GCC_ATOMIC, 1, [Define to 1 if you have GCC-style '__atomic' functions.]) + atomic_type="__atomic"] + ) ) # Prepare CFLAG_VISIBILITY to be used where needed @@ -775,29 +732,15 @@ AS_IF([test -n "$sanitizer_CFLAGS"], [CFLAGS="$CFLAGS $sanitizer_CFLAGS"]) AM_CONDITIONAL([FUZZER], [test "$with_fuzzer" != "no"]) AM_CONDITIONAL([OSS_FUZZ], [test "$with_oss_fuzz" != "no"]) -AS_IF([test "$enable_documentation" = "yes"],[ - -AC_PATH_PROG([SPHINXBUILD], [sphinx-build], [false]) -AS_IF([test "$SPHINXBUILD" = "false"], - [AC_MSG_WARN([missing 'sphinx-build' executable for documentation generation])] -) -AC_PATH_PROG([PDFLATEX], [pdflatex], [false]) -AC_PATH_PROG([MAKEINFO], [makeinfo], [false]) - -]) - -AM_CONDITIONAL([HAVE_SPHINXBUILD], test "$SPHINXBUILD" != "false") -AM_CONDITIONAL([HAVE_PDFLATEX], test "$PDFLATEX" != "false") -AM_CONDITIONAL([HAVE_MAKEINFO], test "$MAKEINFO" != "false") - # Strip -fdebug-prefix-map= parameters from flags for better reproducibility of binaries. filtered_cflags=$(echo -n "$CFLAGS" | \ sed 's/[[^[:alnum:]]]-f[[^[:space:]]]*-prefix-map=[[^[:space:]]]*//g') filtered_cppflags=$(echo -n "$CPPFLAGS" | \ sed 's/[[^[:alnum:]]]-f[[^[:space:]]]*-prefix-map=[[^[:space:]]]*//g') +filtered_config_params=$(echo -n "$ac_configure_args" | \ + sed 's/[[^[:alnum:]]]-f[[^[:space:]]]*-prefix-map=[[^[:space:]]]*//g') -result_msg_base=" Knot DNS $VERSION - +result_msg_base=" Target: $host_os $host_cpu $endianity Compiler: ${CC} CFLAGS: ${filtered_cflags} ${filtered_cppflags} @@ -827,6 +770,7 @@ result_msg_base=" Knot DNS $VERSION XDP support: ${enable_xdp} DoQ support: ${enable_quic} Socket polling: ${socket_polling} + Atomic support: ${atomic_type} Memory allocator: ${with_memory_allocator} Fast zone parser: ${enable_fastparser} Utilities with IDN: ${with_libidn} @@ -834,17 +778,17 @@ result_msg_base=" Knot DNS $VERSION Utilities with Dnstap: ${enable_dnstap} MaxMind DB support: ${enable_maxminddb} Systemd integration: ${enable_systemd} + D-Bus support: ${enable_dbus} POSIX capabilities: ${enable_cap_ng} PKCS #11 support: ${enable_pkcs11} - Ed25519 support: ${enable_ed25519} Ed448 support: ${enable_ed448} - Reproducible signing: ${enable_repro_signing} + Code coverage: ${enable_code_coverage} Sanitizer: ${with_sanitizer} LibFuzzer: ${with_fuzzer} OSS-Fuzz: ${with_oss_fuzz}" -result_msg_esc=$(echo -n "$result_msg_base" | sed '$!s/$/\\n/' | tr -d '\n') +result_msg_esc=$(echo -n " Configure:$filtered_config_params\n$result_msg_base" | sed '$!s/$/\\n/' | tr -d '\n') AC_DEFINE_UNQUOTED([CONFIGURE_SUMMARY],["$result_msg_esc"],[Configure summary]) @@ -875,5 +819,6 @@ AC_CONFIG_FILES([doc/modules.rst], AC_OUTPUT AC_MSG_RESULT([ + Knot DNS $VERSION $result_msg_base ]) diff --git a/distro/Makefile.in b/distro/Makefile.in index c19943d..a492ba7 100644 --- a/distro/Makefile.in +++ b/distro/Makefile.in @@ -259,6 +259,8 @@ infodir = @infodir@ install_sh = @install_sh@ libbpf_CFLAGS = @libbpf_CFLAGS@ libbpf_LIBS = @libbpf_LIBS@ +libdbus_CFLAGS = @libdbus_CFLAGS@ +libdbus_LIBS = @libdbus_LIBS@ libdir = @libdir@ libdnssec_SONAME = @libdnssec_SONAME@ libdnssec_SOVERSION = @libdnssec_SOVERSION@ @@ -270,8 +272,6 @@ libfstrm_CFLAGS = @libfstrm_CFLAGS@ libfstrm_LIBS = @libfstrm_LIBS@ libidn2_CFLAGS = @libidn2_CFLAGS@ libidn2_LIBS = @libidn2_LIBS@ -libidn_CFLAGS = @libidn_CFLAGS@ -libidn_LIBS = @libidn_LIBS@ libknot_SONAME = @libknot_SONAME@ libknot_SOVERSION = @libknot_SOVERSION@ libknot_VERSION_INFO = @libknot_VERSION_INFO@ @@ -289,7 +289,6 @@ libprotobuf_c_CFLAGS = @libprotobuf_c_CFLAGS@ libprotobuf_c_LIBS = @libprotobuf_c_LIBS@ liburcu_CFLAGS = @liburcu_CFLAGS@ liburcu_LIBS = @liburcu_LIBS@ -liburcu_PKGCONFIG = @liburcu_PKGCONFIG@ libxdp_CFLAGS = @libxdp_CFLAGS@ libxdp_LIBS = @libxdp_LIBS@ libzscanner_SONAME = @libzscanner_SONAME@ diff --git a/distro/config/apkg.toml b/distro/config/apkg.toml index 0b9f0eb..3483ac2 100644 --- a/distro/config/apkg.toml +++ b/distro/config/apkg.toml @@ -12,13 +12,5 @@ signature_url = "https://secure.nic.cz/files/knot-dns/knot-{{ version }}.tar.xz. compat = 3 [[distro.aliases]] -name = "el-7" -distro = ["centos == 7", "rhel == 7"] - -[[distro.aliases]] name = "deb-nolibxdp" distro = ["debian == 11", "ubuntu == 20.04", "ubuntu == 22.04"] - -[[distro.aliases]] -name = "deb-noxdp" -distro = ["debian == 10", "ubuntu == 18.04"] diff --git a/distro/pkg/deb-nolibxdp/control b/distro/pkg/deb-nolibxdp/control index ac5211b..30dc1fd 100644 --- a/distro/pkg/deb-nolibxdp/control +++ b/distro/pkg/deb-nolibxdp/control @@ -43,7 +43,7 @@ Architecture: any Depends: adduser, libdnssec9 (= ${binary:Version}), - libknot14 (= ${binary:Version}), + libknot15 (= ${binary:Version}), libzscanner4 (= ${binary:Version}), ${misc:Depends}, ${shlibs:Depends}, @@ -59,7 +59,7 @@ Description: Authoritative domain name server registry and hence is well suited to run anything from the root zone, the top-level domain, to many smaller standard domain names. -Package: libknot14 +Package: libknot15 Architecture: any Depends: ${misc:Depends}, @@ -115,10 +115,9 @@ Architecture: any Depends: libdnssec9 (= ${binary:Version}), libgnutls28-dev, - libknot14 (= ${binary:Version}), + libknot15 (= ${binary:Version}), libzscanner4 (= ${binary:Version}), ${misc:Depends}, - ${shlibs:Depends}, Section: libdevel Description: Knot DNS shared library development files Knot DNS is a fast, authoritative only, high performance, feature @@ -134,7 +133,7 @@ Package: knot-dnsutils Architecture: any Depends: libdnssec9 (= ${binary:Version}), - libknot14 (= ${binary:Version}), + libknot15 (= ${binary:Version}), libzscanner4 (= ${binary:Version}), ${misc:Depends}, ${shlibs:Depends}, @@ -161,7 +160,7 @@ Package: knot-dnssecutils Architecture: any Depends: libdnssec9 (= ${binary:Version}), - libknot14 (= ${binary:Version}), + libknot15 (= ${binary:Version}), libzscanner4 (= ${binary:Version}), ${misc:Depends}, ${shlibs:Depends}, @@ -183,7 +182,7 @@ Package: knot-host Architecture: any Depends: libdnssec9 (= ${binary:Version}), - libknot14 (= ${binary:Version}), + libknot15 (= ${binary:Version}), libzscanner4 (= ${binary:Version}), ${misc:Depends}, ${shlibs:Depends}, @@ -269,7 +268,7 @@ Description: Prometheus exporter for Knot DNS Package: python3-libknot Architecture: all Depends: - libknot14 (= ${binary:Version}), + libknot15 (= ${binary:Version}), ${misc:Depends}, ${python3:Depends}, Section: python diff --git a/distro/pkg/deb-nolibxdp/knot.install b/distro/pkg/deb-nolibxdp/knot.install index 5c716fc..a31224f 100644 --- a/distro/pkg/deb-nolibxdp/knot.install +++ b/distro/pkg/deb-nolibxdp/knot.install @@ -1,5 +1,4 @@ debian/cz.nic.knotd.conf usr/share/dbus-1/system.d/ -debian/ufw/knot etc/ufw/applications.d/ etc/knot/knot.conf usr/sbin/kcatalogprint usr/sbin/keymgr diff --git a/distro/pkg/deb-nolibxdp/libknot14.symbols b/distro/pkg/deb-nolibxdp/libknot14.symbols deleted file mode 100644 index 174d517..0000000 --- a/distro/pkg/deb-nolibxdp/libknot14.symbols +++ /dev/null @@ -1,277 +0,0 @@ -libknot.so.14 libknot14 #MINVER# -* Build-Depends-Package: libknot-dev - KNOT_DB_LMDB_DUPSORT@Base 3.3.0 - KNOT_DB_LMDB_INTEGERKEY@Base 3.3.0 - KNOT_DB_LMDB_MAPASYNC@Base 3.3.0 - KNOT_DB_LMDB_NOSYNC@Base 3.3.0 - KNOT_DB_LMDB_NOTLS@Base 3.3.0 - KNOT_DB_LMDB_RDONLY@Base 3.3.0 - KNOT_DB_LMDB_WRITEMAP@Base 3.3.0 - KNOT_DUMP_STYLE_DEFAULT@Base 3.3.0 - knot_ctl_accept@Base 3.3.0 - knot_ctl_alloc@Base 3.3.0 - knot_ctl_bind@Base 3.3.0 - knot_ctl_bind2@Base 3.3.6 - knot_ctl_close@Base 3.3.0 - knot_ctl_connect@Base 3.3.0 - knot_ctl_free@Base 3.3.0 - knot_ctl_receive@Base 3.3.0 - knot_ctl_send@Base 3.3.0 - knot_ctl_set_timeout@Base 3.3.0 - knot_ctl_unbind@Base 3.3.0 - knot_db_lmdb_api@Base 3.3.0 - knot_db_lmdb_del_exact@Base 3.3.0 - knot_db_lmdb_get_mapsize@Base 3.3.0 - knot_db_lmdb_get_path@Base 3.3.0 - knot_db_lmdb_get_usage@Base 3.3.0 - knot_db_lmdb_iter_del@Base 3.3.0 - knot_db_lmdb_txn_begin@Base 3.3.0 - knot_db_trie_api@Base 3.3.0 - knot_dname_cmp@Base 3.3.0 - knot_dname_copy@Base 3.3.0 - knot_dname_copy_lower@Base 3.3.0 - knot_dname_free@Base 3.3.0 - knot_dname_from_str@Base 3.3.0 - knot_dname_in_bailiwick@Base 3.3.0 - knot_dname_is_case_equal@Base 3.3.0 - knot_dname_is_equal@Base 3.3.0 - knot_dname_labels@Base 3.3.0 - knot_dname_lf@Base 3.3.0 - knot_dname_matched_labels@Base 3.3.0 - knot_dname_prefixlen@Base 3.3.0 - knot_dname_realsize@Base 3.3.0 - knot_dname_replace_suffix@Base 3.3.0 - knot_dname_size@Base 3.3.0 - knot_dname_store@Base 3.3.0 - knot_dname_to_lower@Base 3.3.0 - knot_dname_to_str@Base 3.3.0 - knot_dname_to_wire@Base 3.3.0 - knot_dname_unpack@Base 3.3.0 - knot_dname_wire_check@Base 3.3.0 - knot_dnssec_alg_names@Base 3.3.0 - knot_edns_add_option@Base 3.3.0 - knot_edns_alignment_size@Base 3.3.0 - knot_edns_chain_parse@Base 3.3.0 - knot_edns_chain_size@Base 3.3.0 - knot_edns_chain_write@Base 3.3.0 - knot_edns_client_subnet_get_addr@Base 3.3.0 - knot_edns_client_subnet_parse@Base 3.3.0 - knot_edns_client_subnet_set_addr@Base 3.3.0 - knot_edns_client_subnet_size@Base 3.3.0 - knot_edns_client_subnet_write@Base 3.3.0 - knot_edns_cookie_client_check@Base 3.3.0 - knot_edns_cookie_client_generate@Base 3.3.0 - knot_edns_cookie_parse@Base 3.3.0 - knot_edns_cookie_server_check@Base 3.3.0 - knot_edns_cookie_server_generate@Base 3.3.0 - knot_edns_cookie_size@Base 3.3.0 - knot_edns_cookie_write@Base 3.3.0 - knot_edns_ede_names@Base 3.3.0 - knot_edns_get_ext_rcode@Base 3.3.0 - knot_edns_get_option@Base 3.3.0 - knot_edns_get_options@Base 3.3.0 - knot_edns_get_version@Base 3.3.0 - knot_edns_init@Base 3.3.0 - knot_edns_keepalive_parse@Base 3.3.0 - knot_edns_keepalive_size@Base 3.3.0 - knot_edns_keepalive_write@Base 3.3.0 - knot_edns_opt_names@Base 3.3.0 - knot_edns_reserve_option@Base 3.3.0 - knot_edns_set_ext_rcode@Base 3.3.0 - knot_edns_set_version@Base 3.3.0 - knot_error_from_libdnssec@Base 3.3.0 - knot_eth_mtu@Base 3.3.0 - knot_eth_name_from_addr@Base 3.3.0 - knot_eth_queues@Base 3.3.0 - knot_eth_rss@Base 3.3.0 - knot_eth_vlans@Base 3.3.0 - knot_eth_xdp_mode@Base 3.3.0 - knot_get_obsolete_rdata_descriptor@Base 3.3.0 - knot_get_rdata_descriptor@Base 3.3.0 - knot_naptr_header_size@Base 3.3.0 - knot_opcode_names@Base 3.3.0 - knot_opt_code_to_string@Base 3.3.0 - knot_pkt_begin@Base 3.3.0 - knot_pkt_clear@Base 3.3.0 - knot_pkt_copy@Base 3.3.0 - knot_pkt_ext_rcode@Base 3.3.0 - knot_pkt_ext_rcode_name@Base 3.3.0 - knot_pkt_free@Base 3.3.0 - knot_pkt_init_response@Base 3.3.0 - knot_pkt_new@Base 3.3.0 - knot_pkt_parse@Base 3.3.0 - knot_pkt_parse_question@Base 3.3.0 - knot_pkt_put_question@Base 3.3.0 - knot_pkt_put_rotate@Base 3.3.0 - knot_pkt_reclaim@Base 3.3.0 - knot_pkt_reserve@Base 3.3.0 - knot_probe_alloc@Base 3.3.0 - knot_probe_consume@Base 3.3.0 - knot_probe_data_set@Base 3.3.0 - knot_probe_fd@Base 3.3.0 - knot_probe_free@Base 3.3.0 - knot_probe_produce@Base 3.3.0 - knot_probe_set_consumer@Base 3.3.0 - knot_probe_set_producer@Base 3.3.0 - knot_probe_tcp_rtt@Base 3.3.0 - knot_quic_cleanup@Base 3.3.0 - knot_quic_client@Base 3.3.0 - knot_quic_conn_get_stream@Base 3.3.0 - knot_quic_conn_local_port@Base 3.3.0 - knot_quic_conn_new_stream@Base 3.3.0 - knot_quic_conn_next_timeout@Base 3.3.3 - knot_quic_conn_pin@Base 3.3.0 - knot_quic_conn_rtt@Base 3.3.0 - knot_quic_conn_stream_free@Base 3.3.0 - knot_quic_creds_cert@Base 3.3.0 - knot_quic_free_creds@Base 3.3.0 - knot_quic_handle@Base 3.3.0 - knot_quic_hanle_expiry@Base 3.3.3 - knot_quic_init_creds@Base 3.3.0 - knot_quic_init_creds_peer@Base 3.3.0 - knot_quic_send@Base 3.3.0 - knot_quic_session_available@Base 3.3.0 - knot_quic_session_load@Base 3.3.0 - knot_quic_session_save@Base 3.3.0 - knot_quic_stream_add_data@Base 3.3.0 - knot_quic_stream_get_process@Base 3.3.0 - knot_quic_table_free@Base 3.3.0 - knot_quic_table_new@Base 3.3.0 - knot_quic_table_rem@Base 3.3.0 - knot_quic_table_sweep@Base 3.3.0 - knot_rcode_names@Base 3.3.0 - knot_rdataset_add@Base 3.3.0 - knot_rdataset_at@Base 3.3.0 - knot_rdataset_clear@Base 3.3.0 - knot_rdataset_copy@Base 3.3.0 - knot_rdataset_eq@Base 3.3.0 - knot_rdataset_intersect@Base 3.3.0 - knot_rdataset_intersect2@Base 3.3.0 - knot_rdataset_member@Base 3.3.0 - knot_rdataset_merge@Base 3.3.0 - knot_rdataset_subset@Base 3.3.0 - knot_rdataset_subtract@Base 3.3.0 - knot_rrclass_from_string@Base 3.3.0 - knot_rrclass_to_string@Base 3.3.0 - knot_rrset_add_rdata@Base 3.3.0 - knot_rrset_clear@Base 3.3.0 - knot_rrset_copy@Base 3.3.0 - knot_rrset_equal@Base 3.3.0 - knot_rrset_free@Base 3.3.0 - knot_rrset_is_nsec3rel@Base 3.3.0 - knot_rrset_new@Base 3.3.0 - knot_rrset_rr_from_wire@Base 3.3.0 - knot_rrset_rr_to_canonical@Base 3.3.0 - knot_rrset_size@Base 3.3.0 - knot_rrset_to_wire_extra@Base 3.3.0 - knot_rrset_txt_dump@Base 3.3.0 - knot_rrset_txt_dump_data@Base 3.3.0 - knot_rrset_txt_dump_edns@Base 3.3.0 - knot_rrset_txt_dump_header@Base 3.3.0 - knot_rrtype_additional_needed@Base 3.3.0 - knot_rrtype_from_string@Base 3.3.0 - knot_rrtype_is_dnssec@Base 3.3.0 - knot_rrtype_is_metatype@Base 3.3.0 - knot_rrtype_should_be_lowercased@Base 3.3.0 - knot_rrtype_to_string@Base 3.3.0 - knot_strerror@Base 3.3.0 - knot_svcb_param_names@Base 3.3.0 - knot_tcp_cleanup@Base 3.3.0 - knot_tcp_inbufs_upd@Base 3.3.0 - knot_tcp_outbufs_ack@Base 3.3.0 - knot_tcp_outbufs_add@Base 3.3.0 - knot_tcp_outbufs_can_send@Base 3.3.0 - knot_tcp_outbufs_usage@Base 3.3.0 - knot_tcp_recv@Base 3.3.0 - knot_tcp_reply_data@Base 3.3.0 - knot_tcp_send@Base 3.3.0 - knot_tcp_sweep@Base 3.3.0 - knot_tcp_table_free@Base 3.3.0 - knot_tcp_table_new@Base 3.3.0 - knot_tsig_add@Base 3.3.0 - knot_tsig_append@Base 3.3.0 - knot_tsig_client_check@Base 3.3.0 - knot_tsig_client_check_next@Base 3.3.0 - knot_tsig_create_rdata@Base 3.3.0 - knot_tsig_key_copy@Base 3.3.0 - knot_tsig_key_deinit@Base 3.3.0 - knot_tsig_key_init@Base 3.3.0 - knot_tsig_key_init_file@Base 3.3.0 - knot_tsig_key_init_str@Base 3.3.0 - knot_tsig_rcode_names@Base 3.3.0 - knot_tsig_rdata_alg@Base 3.3.0 - knot_tsig_rdata_alg_name@Base 3.3.0 - knot_tsig_rdata_error@Base 3.3.0 - knot_tsig_rdata_fudge@Base 3.3.0 - knot_tsig_rdata_is_ok@Base 3.3.0 - knot_tsig_rdata_mac@Base 3.3.0 - knot_tsig_rdata_mac_length@Base 3.3.0 - knot_tsig_rdata_orig_id@Base 3.3.0 - knot_tsig_rdata_other_data@Base 3.3.0 - knot_tsig_rdata_other_data_length@Base 3.3.0 - knot_tsig_rdata_set_fudge@Base 3.3.0 - knot_tsig_rdata_set_mac@Base 3.3.0 - knot_tsig_rdata_set_orig_id@Base 3.3.0 - knot_tsig_rdata_set_other_data@Base 3.3.0 - knot_tsig_rdata_set_time_signed@Base 3.3.0 - knot_tsig_rdata_time_signed@Base 3.3.0 - knot_tsig_rdata_tsig_timers_length@Base 3.3.0 - knot_tsig_rdata_tsig_variables_length@Base 3.3.0 - knot_tsig_server_check@Base 3.3.0 - knot_tsig_sign@Base 3.3.0 - knot_tsig_sign_next@Base 3.3.0 - knot_tsig_wire_maxsize@Base 3.3.0 - knot_tsig_wire_size@Base 3.3.0 - knot_xdp_deinit@Base 3.3.0 - knot_xdp_init@Base 3.3.0 - knot_xdp_recv@Base 3.3.0 - knot_xdp_recv_finish@Base 3.3.0 - knot_xdp_reply_alloc@Base 3.3.0 - knot_xdp_send@Base 3.3.0 - knot_xdp_send_alloc@Base 3.3.0 - knot_xdp_send_finish@Base 3.3.0 - knot_xdp_send_free@Base 3.3.0 - knot_xdp_send_prepare@Base 3.3.0 - knot_xdp_socket_info@Base 3.3.0 - knot_xdp_socket_fd@Base 3.3.0 - yp_addr@Base 3.3.0 - yp_addr_noport@Base 3.3.0 - yp_addr_noport_to_bin@Base 3.3.0 - yp_addr_noport_to_txt@Base 3.3.0 - yp_addr_range_to_bin@Base 3.3.0 - yp_addr_range_to_txt@Base 3.3.0 - yp_addr_to_bin@Base 3.3.0 - yp_addr_to_txt@Base 3.3.0 - yp_base64_to_bin@Base 3.3.0 - yp_base64_to_txt@Base 3.3.0 - yp_bool_to_bin@Base 3.3.0 - yp_bool_to_txt@Base 3.3.0 - yp_deinit@Base 3.3.0 - yp_dname_to_bin@Base 3.3.0 - yp_dname_to_txt@Base 3.3.0 - yp_format_id@Base 3.3.0 - yp_format_key0@Base 3.3.0 - yp_format_key1@Base 3.3.0 - yp_hex_to_bin@Base 3.3.0 - yp_hex_to_txt@Base 3.3.0 - yp_init@Base 3.3.0 - yp_int_to_bin@Base 3.3.0 - yp_int_to_txt@Base 3.3.0 - yp_item_to_bin@Base 3.3.0 - yp_item_to_txt@Base 3.3.0 - yp_option_to_bin@Base 3.3.0 - yp_option_to_txt@Base 3.3.0 - yp_parse@Base 3.3.0 - yp_schema_check_deinit@Base 3.3.0 - yp_schema_check_init@Base 3.3.0 - yp_schema_check_parser@Base 3.3.0 - yp_schema_check_str@Base 3.3.0 - yp_schema_copy@Base 3.3.0 - yp_schema_find@Base 3.3.0 - yp_schema_free@Base 3.3.0 - yp_schema_merge@Base 3.3.0 - yp_schema_purge_dynamic@Base 3.3.0 - yp_set_input_file@Base 3.3.0 - yp_set_input_string@Base 3.3.0 - yp_str_to_bin@Base 3.3.0 - yp_str_to_txt@Base 3.3.0 diff --git a/distro/pkg/deb-nolibxdp/libknot14.install b/distro/pkg/deb-nolibxdp/libknot15.install index f9b9f93..f9b9f93 100644 --- a/distro/pkg/deb-nolibxdp/libknot14.install +++ b/distro/pkg/deb-nolibxdp/libknot15.install diff --git a/distro/pkg/deb-nolibxdp/libknot15.symbols b/distro/pkg/deb-nolibxdp/libknot15.symbols new file mode 100644 index 0000000..77dd5b0 --- /dev/null +++ b/distro/pkg/deb-nolibxdp/libknot15.symbols @@ -0,0 +1,290 @@ +libknot.so.15 libknot15 #MINVER# +* Build-Depends-Package: libknot-dev + KNOT_DB_LMDB_DUPSORT@Base 3.4.0 + KNOT_DB_LMDB_INTEGERKEY@Base 3.4.0 + KNOT_DB_LMDB_MAPASYNC@Base 3.4.0 + KNOT_DB_LMDB_NOSYNC@Base 3.4.0 + KNOT_DB_LMDB_NOTLS@Base 3.4.0 + KNOT_DB_LMDB_RDONLY@Base 3.4.0 + KNOT_DB_LMDB_WRITEMAP@Base 3.4.0 + KNOT_DUMP_STYLE_DEFAULT@Base 3.4.0 + knot_creds_cert@Base 3.4.0 + knot_creds_free@Base 3.4.0 + knot_creds_init@Base 3.4.0 + knot_creds_init_peer@Base 3.4.0 + knot_creds_update@Base 3.4.0 + knot_ctl_accept@Base 3.4.0 + knot_ctl_alloc@Base 3.4.0 + knot_ctl_bind@Base 3.4.0 + knot_ctl_clone@Base 3.4.0 + knot_ctl_close@Base 3.4.0 + knot_ctl_connect@Base 3.4.0 + knot_ctl_free@Base 3.4.0 + knot_ctl_receive@Base 3.4.0 + knot_ctl_send@Base 3.4.0 + knot_ctl_set_timeout@Base 3.4.0 + knot_ctl_unbind@Base 3.4.0 + knot_db_lmdb_api@Base 3.4.0 + knot_db_lmdb_del_exact@Base 3.4.0 + knot_db_lmdb_get_mapsize@Base 3.4.0 + knot_db_lmdb_get_path@Base 3.4.0 + knot_db_lmdb_get_usage@Base 3.4.0 + knot_db_lmdb_iter_del@Base 3.4.0 + knot_db_lmdb_txn_begin@Base 3.4.0 + knot_db_trie_api@Base 3.4.0 + knot_dname_cmp@Base 3.4.0 + knot_dname_copy@Base 3.4.0 + knot_dname_copy_lower@Base 3.4.0 + knot_dname_free@Base 3.4.0 + knot_dname_from_str@Base 3.4.0 + knot_dname_in_bailiwick@Base 3.4.0 + knot_dname_is_case_equal@Base 3.4.0 + knot_dname_is_equal@Base 3.4.0 + knot_dname_labels@Base 3.4.0 + knot_dname_lf@Base 3.4.0 + knot_dname_matched_labels@Base 3.4.0 + knot_dname_prefixlen@Base 3.4.0 + knot_dname_realsize@Base 3.4.0 + knot_dname_replace_suffix@Base 3.4.0 + knot_dname_size@Base 3.4.0 + knot_dname_store@Base 3.4.0 + knot_dname_to_lower@Base 3.4.0 + knot_dname_to_str@Base 3.4.0 + knot_dname_to_wire@Base 3.4.0 + knot_dname_unpack@Base 3.4.0 + knot_dname_wire_check@Base 3.4.0 + knot_dnssec_alg_names@Base 3.4.0 + knot_edns_add_option@Base 3.4.0 + knot_edns_alignment_size@Base 3.4.0 + knot_edns_chain_parse@Base 3.4.0 + knot_edns_chain_size@Base 3.4.0 + knot_edns_chain_write@Base 3.4.0 + knot_edns_client_subnet_get_addr@Base 3.4.0 + knot_edns_client_subnet_parse@Base 3.4.0 + knot_edns_client_subnet_set_addr@Base 3.4.0 + knot_edns_client_subnet_size@Base 3.4.0 + knot_edns_client_subnet_write@Base 3.4.0 + knot_edns_cookie_client_check@Base 3.4.0 + knot_edns_cookie_client_generate@Base 3.4.0 + knot_edns_cookie_parse@Base 3.4.0 + knot_edns_cookie_server_check@Base 3.4.0 + knot_edns_cookie_server_generate@Base 3.4.0 + knot_edns_cookie_size@Base 3.4.0 + knot_edns_cookie_write@Base 3.4.0 + knot_edns_ede_names@Base 3.4.0 + knot_edns_get_ext_rcode@Base 3.4.0 + knot_edns_get_option@Base 3.4.0 + knot_edns_get_options@Base 3.4.0 + knot_edns_get_version@Base 3.4.0 + knot_edns_init@Base 3.4.0 + knot_edns_keepalive_parse@Base 3.4.0 + knot_edns_keepalive_size@Base 3.4.0 + knot_edns_keepalive_write@Base 3.4.0 + knot_edns_opt_names@Base 3.4.0 + knot_edns_reserve_option@Base 3.4.0 + knot_edns_set_ext_rcode@Base 3.4.0 + knot_edns_set_version@Base 3.4.0 + knot_error_from_libdnssec@Base 3.4.0 + knot_eth_mtu@Base 3.4.0 + knot_eth_name_from_addr@Base 3.4.0 + knot_eth_queues@Base 3.4.0 + knot_eth_rss@Base 3.4.0 + knot_eth_vlans@Base 3.4.0 + knot_eth_xdp_mode@Base 3.4.0 + knot_get_obsolete_rdata_descriptor@Base 3.4.0 + knot_get_rdata_descriptor@Base 3.4.0 + knot_naptr_header_size@Base 3.4.0 + knot_opcode_names@Base 3.4.0 + knot_opt_code_to_string@Base 3.4.0 + knot_pkt_begin@Base 3.4.0 + knot_pkt_clear@Base 3.4.0 + knot_pkt_copy@Base 3.4.0 + knot_pkt_ext_rcode@Base 3.4.0 + knot_pkt_ext_rcode_name@Base 3.4.0 + knot_pkt_free@Base 3.4.0 + knot_pkt_init_response@Base 3.4.0 + knot_pkt_new@Base 3.4.0 + knot_pkt_parse@Base 3.4.0 + knot_pkt_parse_question@Base 3.4.0 + knot_pkt_put_question@Base 3.4.0 + knot_pkt_put_rotate@Base 3.4.0 + knot_pkt_reclaim@Base 3.4.0 + knot_pkt_reserve@Base 3.4.0 + knot_probe_alloc@Base 3.4.0 + knot_probe_consume@Base 3.4.0 + knot_probe_data_set@Base 3.4.0 + knot_probe_fd@Base 3.4.0 + knot_probe_free@Base 3.4.0 + knot_probe_produce@Base 3.4.0 + knot_probe_set_consumer@Base 3.4.0 + knot_probe_set_producer@Base 3.4.0 + knot_probe_tcp_rtt@Base 3.4.0 + knot_quic_cleanup@Base 3.4.0 + knot_quic_client@Base 3.4.0 + knot_quic_conn_block@Base 3.4.0 + knot_quic_conn_get_stream@Base 3.4.0 + knot_quic_conn_local_port@Base 3.4.0 + knot_quic_conn_new_stream@Base 3.4.0 + knot_quic_conn_next_timeout@Base 3.4.0 + knot_quic_conn_rtt@Base 3.4.0 + knot_quic_conn_stream_free@Base 3.4.0 + knot_quic_handle@Base 3.4.0 + knot_quic_hanle_expiry@Base 3.4.0 + knot_quic_send@Base 3.4.0 + knot_quic_session_available@Base 3.4.0 + knot_quic_session_load@Base 3.4.0 + knot_quic_session_save@Base 3.4.0 + knot_quic_stream_add_data@Base 3.4.0 + knot_quic_stream_get_process@Base 3.4.0 + knot_quic_table_free@Base 3.4.0 + knot_quic_table_new@Base 3.4.0 + knot_quic_table_rem@Base 3.4.0 + knot_quic_table_sweep@Base 3.4.0 + knot_rcode_names@Base 3.4.0 + knot_rdataset_add@Base 3.4.0 + knot_rdataset_at@Base 3.4.0 + knot_rdataset_clear@Base 3.4.0 + knot_rdataset_copy@Base 3.4.0 + knot_rdataset_eq@Base 3.4.0 + knot_rdataset_intersect@Base 3.4.0 + knot_rdataset_intersect2@Base 3.4.0 + knot_rdataset_member@Base 3.4.0 + knot_rdataset_merge@Base 3.4.0 + knot_rdataset_subset@Base 3.4.0 + knot_rdataset_subtract@Base 3.4.0 + knot_rrclass_from_string@Base 3.4.0 + knot_rrclass_to_string@Base 3.4.0 + knot_rrset_add_rdata@Base 3.4.0 + knot_rrset_clear@Base 3.4.0 + knot_rrset_copy@Base 3.4.0 + knot_rrset_equal@Base 3.4.0 + knot_rrset_free@Base 3.4.0 + knot_rrset_is_nsec3rel@Base 3.4.0 + knot_rrset_new@Base 3.4.0 + knot_rrset_rr_from_wire@Base 3.4.0 + knot_rrset_rr_to_canonical@Base 3.4.0 + knot_rrset_size@Base 3.4.0 + knot_rrset_to_wire_extra@Base 3.4.0 + knot_rrset_txt_dump@Base 3.4.0 + knot_rrset_txt_dump_data@Base 3.4.0 + knot_rrset_txt_dump_edns@Base 3.4.0 + knot_rrset_txt_dump_header@Base 3.4.0 + knot_rrtype_additional_needed@Base 3.4.0 + knot_rrtype_from_string@Base 3.4.0 + knot_rrtype_is_dnssec@Base 3.4.0 + knot_rrtype_is_metatype@Base 3.4.0 + knot_rrtype_should_be_lowercased@Base 3.4.0 + knot_rrtype_to_string@Base 3.4.0 + knot_strerror@Base 3.4.0 + knot_svcb_param_names@Base 3.4.0 + knot_tcp_cleanup@Base 3.4.0 + knot_tcp_inbufs_upd@Base 3.4.0 + knot_tcp_outbufs_ack@Base 3.4.0 + knot_tcp_outbufs_add@Base 3.4.0 + knot_tcp_outbufs_can_send@Base 3.4.0 + knot_tcp_outbufs_usage@Base 3.4.0 + knot_tcp_recv@Base 3.4.0 + knot_tcp_reply_data@Base 3.4.0 + knot_tcp_send@Base 3.4.0 + knot_tcp_sweep@Base 3.4.0 + knot_tcp_table_free@Base 3.4.0 + knot_tcp_table_new@Base 3.4.0 + knot_tls_conn_block@Base 3.4.0 + knot_tls_conn_del@Base 3.4.0 + knot_tls_conn_new@Base 3.4.0 + knot_tls_ctx_free@Base 3.4.0 + knot_tls_ctx_new@Base 3.4.0 + knot_tls_handshake@Base 3.4.0 + knot_tls_pin@Base 3.4.0 + knot_tls_pin_check@Base 3.4.0 + knot_tls_recv_dns@Base 3.4.0 + knot_tls_send_dns@Base 3.4.0 + knot_tls_session@Base 3.4.0 + knot_tsig_add@Base 3.4.0 + knot_tsig_append@Base 3.4.0 + knot_tsig_client_check@Base 3.4.0 + knot_tsig_client_check_next@Base 3.4.0 + knot_tsig_create_rdata@Base 3.4.0 + knot_tsig_key_copy@Base 3.4.0 + knot_tsig_key_deinit@Base 3.4.0 + knot_tsig_key_init@Base 3.4.0 + knot_tsig_key_init_file@Base 3.4.0 + knot_tsig_key_init_str@Base 3.4.0 + knot_tsig_rcode_names@Base 3.4.0 + knot_tsig_rdata_alg@Base 3.4.0 + knot_tsig_rdata_alg_name@Base 3.4.0 + knot_tsig_rdata_error@Base 3.4.0 + knot_tsig_rdata_fudge@Base 3.4.0 + knot_tsig_rdata_is_ok@Base 3.4.0 + knot_tsig_rdata_mac@Base 3.4.0 + knot_tsig_rdata_mac_length@Base 3.4.0 + knot_tsig_rdata_orig_id@Base 3.4.0 + knot_tsig_rdata_other_data@Base 3.4.0 + knot_tsig_rdata_other_data_length@Base 3.4.0 + knot_tsig_rdata_set_fudge@Base 3.4.0 + knot_tsig_rdata_set_mac@Base 3.4.0 + knot_tsig_rdata_set_orig_id@Base 3.4.0 + knot_tsig_rdata_set_other_data@Base 3.4.0 + knot_tsig_rdata_set_time_signed@Base 3.4.0 + knot_tsig_rdata_time_signed@Base 3.4.0 + knot_tsig_rdata_tsig_timers_length@Base 3.4.0 + knot_tsig_rdata_tsig_variables_length@Base 3.4.0 + knot_tsig_server_check@Base 3.4.0 + knot_tsig_sign@Base 3.4.0 + knot_tsig_sign_next@Base 3.4.0 + knot_tsig_wire_maxsize@Base 3.4.0 + knot_tsig_wire_size@Base 3.4.0 + knot_xdp_deinit@Base 3.4.0 + knot_xdp_init@Base 3.4.0 + knot_xdp_recv@Base 3.4.0 + knot_xdp_recv_finish@Base 3.4.0 + knot_xdp_reply_alloc@Base 3.4.0 + knot_xdp_send@Base 3.4.0 + knot_xdp_send_alloc@Base 3.4.0 + knot_xdp_send_finish@Base 3.4.0 + knot_xdp_send_free@Base 3.4.0 + knot_xdp_send_prepare@Base 3.4.0 + knot_xdp_socket_info@Base 3.4.0 + knot_xdp_socket_stats@Base 3.4.0 + knot_xdp_socket_fd@Base 3.4.0 + yp_addr@Base 3.4.0 + yp_addr_noport@Base 3.4.0 + yp_addr_noport_to_bin@Base 3.4.0 + yp_addr_noport_to_txt@Base 3.4.0 + yp_addr_range_to_bin@Base 3.4.0 + yp_addr_range_to_txt@Base 3.4.0 + yp_addr_to_bin@Base 3.4.0 + yp_addr_to_txt@Base 3.4.0 + yp_base64_to_bin@Base 3.4.0 + yp_base64_to_txt@Base 3.4.0 + yp_bool_to_bin@Base 3.4.0 + yp_bool_to_txt@Base 3.4.0 + yp_deinit@Base 3.4.0 + yp_dname_to_bin@Base 3.4.0 + yp_dname_to_txt@Base 3.4.0 + yp_format_id@Base 3.4.0 + yp_format_key0@Base 3.4.0 + yp_format_key1@Base 3.4.0 + yp_hex_to_bin@Base 3.4.0 + yp_hex_to_txt@Base 3.4.0 + yp_init@Base 3.4.0 + yp_int_to_bin@Base 3.4.0 + yp_int_to_txt@Base 3.4.0 + yp_item_to_bin@Base 3.4.0 + yp_item_to_txt@Base 3.4.0 + yp_option_to_bin@Base 3.4.0 + yp_option_to_txt@Base 3.4.0 + yp_parse@Base 3.4.0 + yp_schema_check_deinit@Base 3.4.0 + yp_schema_check_init@Base 3.4.0 + yp_schema_check_parser@Base 3.4.0 + yp_schema_check_str@Base 3.4.0 + yp_schema_copy@Base 3.4.0 + yp_schema_find@Base 3.4.0 + yp_schema_free@Base 3.4.0 + yp_schema_merge@Base 3.4.0 + yp_schema_purge_dynamic@Base 3.4.0 + yp_set_input_file@Base 3.4.0 + yp_set_input_string@Base 3.4.0 + yp_str_to_bin@Base 3.4.0 + yp_str_to_txt@Base 3.4.0 diff --git a/distro/pkg/deb-nolibxdp/rules b/distro/pkg/deb-nolibxdp/rules index 82cc34b..c5c81d0 100755 --- a/distro/pkg/deb-nolibxdp/rules +++ b/distro/pkg/deb-nolibxdp/rules @@ -36,11 +36,9 @@ BASE_VERSION := $(shell echo $(DEB_VERSION) | sed 's/^\([^.]\+\.[^.]\+\).*/\1/') # invocation due to bug in dh-python's plugin_pyproject.py wheel unpack export PYBUILD_SYSTEM = distutils - %: dh $@ \ - --exclude=.la --exclude=example.com.zone \ - --with python3 + --with python3 override_dh_auto_configure: dh_auto_configure -- \ @@ -95,7 +93,7 @@ ifeq (,$(filter nocheck,$(DEB_BUILD_OPTIONS))) endif override_dh_missing: - dh_missing --fail-missing + dh_missing --exclude=.la --fail-missing override_dh_installchangelogs: dh_installchangelogs NEWS diff --git a/distro/pkg/deb-nolibxdp/ufw/knot b/distro/pkg/deb-nolibxdp/ufw/knot deleted file mode 100644 index ee36916..0000000 --- a/distro/pkg/deb-nolibxdp/ufw/knot +++ /dev/null @@ -1,4 +0,0 @@ -[Knot] -title=Internet Domain Name Server -description=The Knot DNS implements an Internet domain name server. -ports=53 diff --git a/distro/pkg/deb-noxdp/changelog b/distro/pkg/deb-noxdp/changelog deleted file mode 100644 index 123f92b..0000000 --- a/distro/pkg/deb-noxdp/changelog +++ /dev/null @@ -1,6 +0,0 @@ -knot ({{ version }}-cznic.{{ release }}) unstable; urgency=medium - - * upstream package - * see https://www.knot-dns.cz - - -- Knot DNS <knot-dns@labs.nic.cz> {{ now }} diff --git a/distro/pkg/deb-noxdp/clean b/distro/pkg/deb-noxdp/clean deleted file mode 100644 index b2a9f3f..0000000 --- a/distro/pkg/deb-noxdp/clean +++ /dev/null @@ -1,2 +0,0 @@ -doc/modules -.pybuild/ diff --git a/distro/pkg/deb-noxdp/compat b/distro/pkg/deb-noxdp/compat deleted file mode 100644 index b4de394..0000000 --- a/distro/pkg/deb-noxdp/compat +++ /dev/null @@ -1 +0,0 @@ -11 diff --git a/distro/pkg/deb-noxdp/control b/distro/pkg/deb-noxdp/control deleted file mode 100644 index be9dd3f..0000000 --- a/distro/pkg/deb-noxdp/control +++ /dev/null @@ -1,288 +0,0 @@ -Source: knot -Section: net -Priority: optional -Maintainer: Knot DNS <knot-dns@labs.nic.cz> -Uploaders: - Jakub Ružička <jakub.ruzicka@nic.cz>, - Daniel Salzman <daniel.salzman@nic.cz>, -Build-Depends-Indep: - python3-setuptools, - python3-sphinx, -Build-Depends: - autoconf, - automake, - debhelper (>= 11), - dh-python, - libcap-ng-dev, - libedit-dev, - libfstrm-dev, - libgnutls28-dev, - libidn2-dev, - liblmdb-dev, - libmaxminddb-dev, - libmnl-dev, - libnghttp2-dev, - libprotobuf-c-dev, - libsofthsm2 <!nocheck>, - libsystemd-dev [linux-any] | libsystemd-daemon-dev [linux-any], - libsystemd-dev [linux-any] | libsystemd-journal-dev [linux-any], - libtool, - liburcu-dev, - pkg-config, - protobuf-c-compiler, - python3-all, -Standards-Version: 4.5.0 -Homepage: https://www.knot-dns.cz/ -Vcs-Browser: https://gitlab.nic.cz/knot/knot-dns -Vcs-Git: https://gitlab.nic.cz/knot/knot-dns.git -Rules-Requires-Root: no - -Package: knot -Architecture: any -Depends: - adduser, - libdnssec9 (= ${binary:Version}), - libknot14 (= ${binary:Version}), - libzscanner4 (= ${binary:Version}), - lsb-base (>= 3.0-6), - ${misc:Depends}, - ${shlibs:Depends}, -Pre-Depends: - ${misc:Pre-Depends}, -Suggests: - systemd, -Description: Authoritative domain name server - Knot DNS is a fast, authoritative only, high performance, feature - full and open source name server. - . - Knot DNS is developed by CZ.NIC Labs, the R&D department of .CZ - registry and hence is well suited to run anything from the root - zone, the top-level domain, to many smaller standard domain names. - -Package: libknot14 -Architecture: any -Multi-Arch: same -Depends: - ${misc:Depends}, - ${shlibs:Depends}, -Section: libs -Description: DNS shared library from Knot DNS - Knot DNS is a fast, authoritative only, high performance, feature - full and open source name server. - . - Knot DNS is developed by CZ.NIC Labs, the R&D department of .CZ - registry and hence is well suited to run anything from the root - zone, the top-level domain, to many smaller standard domain names. - . - This package provides a DNS shared library used by Knot DNS and - Knot Resolver. - -Package: libzscanner4 -Architecture: any -Multi-Arch: same -Depends: - ${misc:Depends}, - ${shlibs:Depends}, -Section: libs -Description: DNS zone-parsing shared library from Knot DNS - Knot DNS is a fast, authoritative only, high performance, feature - full and open source name server. - . - Knot DNS is developed by CZ.NIC Labs, the R&D department of .CZ - registry and hence is well suited to run anything from the root - zone, the top-level domain, to many smaller standard domain names. - . - This package provides a fast zone parser shared library used by Knot - DNS and Knot Resolver. - -Package: libdnssec9 -Architecture: any -Multi-Arch: same -Depends: - ${misc:Depends}, - ${shlibs:Depends}, -Section: libs -Description: DNSSEC shared library from Knot DNS - Knot DNS is a fast, authoritative only, high performance, feature - full and open source name server. - . - Knot DNS is developed by CZ.NIC Labs, the R&D department of .CZ - registry and hence is well suited to run anything from the root - zone, the top-level domain, to many smaller standard domain names. - . - This package provides common DNSSEC shared library used by Knot DNS - and Knot Resolver. - -Package: libknot-dev -Architecture: any -Depends: - libdnssec9 (= ${binary:Version}), - libgnutls28-dev, - libknot14 (= ${binary:Version}), - libzscanner4 (= ${binary:Version}), - ${misc:Depends}, - ${shlibs:Depends}, -Section: libdevel -Description: Knot DNS shared library development files - Knot DNS is a fast, authoritative only, high performance, feature - full and open source name server. - . - Knot DNS is developed by CZ.NIC Labs, the R&D department of .CZ - registry and hence is well suited to run anything from the root - zone, the top-level domain, to many smaller standard domain names. - . - This package provides development files for shared libraries from Knot DNS. - -Package: knot-dnsutils -Architecture: any -Depends: - libdnssec9 (= ${binary:Version}), - libknot14 (= ${binary:Version}), - libzscanner4 (= ${binary:Version}), - ${misc:Depends}, - ${shlibs:Depends}, -Description: DNS clients provided with Knot DNS (kdig, knsupdate) - Knot DNS is a fast, authoritative only, high performance, feature - full and open source name server. - . - Knot DNS is developed by CZ.NIC Labs, the R&D department of .CZ - registry and hence is well suited to run anything from the root - zone, the top-level domain, to many smaller standard domain names. - . - This package delivers various DNS client programs from Knot DNS. - . - - kdig - query a DNS server in various ways - - knsupdate - perform dynamic updates (See RFC2136) - . - Those clients were designed to be almost 1:1 compatible with BIND dnsutils, - but they provide some enhancements, which are documented. - . - WARNING: knslookup is not provided as it is considered obsolete. - -Package: knot-dnssecutils -Architecture: any -Depends: - libdnssec9 (= ${binary:Version}), - libknot14 (= ${binary:Version}), - libzscanner4 (= ${binary:Version}), - ${misc:Depends}, - ${shlibs:Depends}, -Description: DNSSEC tools provided with Knot DNS - Knot DNS is a fast, authoritative only, high performance, feature - full and open source name server. - . - Knot DNS is developed by CZ.NIC Labs, the R&D department of .CZ - registry and hence is well suited to run anything from the root - zone, the top-level domain, to many smaller standard domain names. - . - This package delivers various DNSSEC tools from Knot DNS. - . - - kzonecheck - - kzonesign - - knsec3hash - -Package: knot-host -Architecture: any -Depends: - libdnssec9 (= ${binary:Version}), - libknot14 (= ${binary:Version}), - libzscanner4 (= ${binary:Version}), - ${misc:Depends}, - ${shlibs:Depends}, -Description: Version of 'host' bundled with Knot DNS - Knot DNS is a fast, authoritative only, high performance, feature - full and open source name server. - . - Knot DNS is developed by CZ.NIC Labs, the R&D department of .CZ - registry and hence is well suited to run anything from the root - zone, the top-level domain, to many smaller standard domain names. - . - This package provides the 'host' program from Knot DNS. This program is - designed to be almost 1:1 compatible with BIND 9.x 'host' program. - -Package: knot-module-dnstap -Architecture: any -Multi-Arch: same -Depends: - knot (= ${binary:Version}), - ${misc:Depends}, - ${shlibs:Depends}, -Description: dnstap module for Knot DNS - Knot DNS is a fast, authoritative only, high performance, feature - full and open source name server. - . - Knot DNS is developed by CZ.NIC Labs, the R&D department of .CZ - registry and hence is well suited to run anything from the root - zone, the top-level domain, to many smaller standard domain names. - . - This package contains dnstap module for logging DNS traffic. - -Package: knot-module-geoip -Architecture: any -Multi-Arch: same -Depends: - knot (= ${binary:Version}), - ${misc:Depends}, - ${shlibs:Depends}, -Description: geoip module for Knot DNS - Knot DNS is a fast, authoritative only, high performance, feature - full and open source name server. - . - Knot DNS is developed by CZ.NIC Labs, the R&D department of .CZ - registry and hence is well suited to run anything from the root - zone, the top-level domain, to many smaller standard domain names. - . - This package contains geoip module for geography-based responses. - -Package: knot-doc -Architecture: all -Multi-Arch: foreign -Depends: - libjs-jquery, - libjs-sphinxdoc, - libjs-underscore, - ${misc:Depends}, -Section: doc -Description: Documentation for Knot DNS - Knot DNS is a fast, authoritative only, high performance, feature - full and open source name server. - . - Knot DNS is developed by CZ.NIC Labs, the R&D department of .CZ - registry and hence is well suited to run anything from the root - zone, the top-level domain, to many smaller standard domain names. - . - This package provides various documents that are useful for - maintaining a working Knot DNS installation. - -Package: knot-exporter -Architecture: all -Depends: - ${misc:Depends}, - ${python3:Depends}, -Section: python -Description: Prometheus exporter for Knot DNS - Knot DNS is a fast, authoritative only, high performance, feature - full and open source name server. - . - Knot DNS is developed by CZ.NIC Labs, the R&D department of .CZ - registry and hence is well suited to run anything from the root - zone, the top-level domain, to many smaller standard domain names. - . - This package provides Python Prometheus exporter for Knot DNS. - -Package: python3-libknot -Architecture: all -Depends: - libknot14 (= ${binary:Version}), - ${misc:Depends}, - ${python3:Depends}, -Section: python -Description: Python bindings for libknot - Knot DNS is a fast, authoritative only, high performance, feature - full and open source name server. - . - Knot DNS is developed by CZ.NIC Labs, the R&D department of .CZ - registry and hence is well suited to run anything from the root - zone, the top-level domain, to many smaller standard domain names. - . - This package provides Python bindings for the libknot shared library. diff --git a/distro/pkg/deb-noxdp/copyright b/distro/pkg/deb-noxdp/copyright deleted file mode 100644 index 20c8b97..0000000 --- a/distro/pkg/deb-noxdp/copyright +++ /dev/null @@ -1,179 +0,0 @@ -Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ -Upstream-Name: Knot DNS -Upstream-Contact: knot-dns@labs.nic.cz -Source: https://secure.nic.cz/files/knot-dns/ - -Files: * -Copyright: 2011-2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> -License: GPL-3+ - -Files: m4/* -Copyright: 2011-2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> - 1996-2001, 2003-2015 Free Software Foundation, Inc. -License: GPL-3+ - -Files: install-sh -Copyright: 1994 X Consortium -License: MIT - -Files: debian/* distro/pkg/deb/* -Copyright: 2011-2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> - 2011 Ondřej Surý <ondrej@debian.org> -License: GPL-3+ - -Files: tests/tap/* -Copyright: 2000-2001, 2004, 2006-2012 Russ Allbery <rra@stanford.edu> - 2006, 2007, 2008, 2013 The Board of Trustees of the Leland Stanford Junior University -License: MIT - -Files: tests/tap/files.* -Copyright: 2011-2019 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> -License: GPL-3+ - -Files: src/contrib/dnstap/* -Copyright: 2014, Farsight Security, Inc. <software@farsightsecurity.com> - 2011-2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> -License: GPL-3+ - -Files: src/contrib/libngtcp2/* -Copyright: 2016-2023 ngtcp2 contributors - 2012-2017 nghttp2 contributors -License: MIT - -Files: src/contrib/musl/* -Copyright: 2005-2020 Rich Felker, et al. -License: MIT - -Files: src/contrib/openbsd/siphash.* -Copyright: 2013 Andre Oppermann <andre@FreeBSD.org> -License: BSD-3-Clause - -Files: src/contrib/openbsd/strl* -Copyright: 1998 Todd C. Miller <Todd.Miller@courtesan.com> -License: 0BSD - -Files: src/contrib/proxyv2/* -Copyright: 2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> - 2021 Fastly, Inc. -License: GPL-3+ - -Files: src/contrib/qp-trie/* -Copyright: 2011-2019 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> - 2018 Tony Finch <dot@dotat.at> -License: GPL-3+ - -Files: src/contrib/ucw/* -Copyright: 2011-2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> - 1997-2017 Martin Mares <mj@ucw.cz> - 2007 Pavel Charvat <pchar@ucw.cz> - 2012 Ondrej Filip <feela@network.cz> -License: LGPL-2.0 - -Files: src/contrib/ucw/heap.h -Copyright: 2011-2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> -License: GPL-3+ - -Files: src/contrib/url-parser/* -Copyright: 2020 Igor Sysoev - 2020 Nginx, Inc. - 2020 Joyent, Inc. -License: MIT - -Files: src/contrib/vpool/* -Copyright: 2006, 2008 Alexey Vatchenko <av@bsdua.org> -License: 0BSD - -Files: tests-fuzz/main.c -Copyright: 2011-2019 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> - 2017 Tim Ruehsen -License: MIT - -License: GPL-3+ - 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 3 of the License, 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 <https://www.gnu.org/licenses/>. - . - On Debian systems, the full text of the GNU General Public License - version 3 can be found in the file `/usr/share/common-licenses/GPL-3'. - -License: LGPL-2.0 - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - . - This library 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 - Library General Public License for more details. - . - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the - Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, - Boston, MA 02110-1301, USA. - -License: 0BSD - Permission to use, copy, modify, and distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - . - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -License: BSD-3-Clause - Redistribution and use in source and binary forms, with or without modification, - are permitted provided that the following conditions are met: - 1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - 3. Neither the name of the copyright holder nor the names of its contributors - may be used to endorse or promote products derived from this software without - specific prior written permission. - . - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, - INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE - OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - OF THE POSSIBILITY OF SUCH DAMAGE. - -License: MIT - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files (the - "Software"), to deal in the Software without restriction, including - without limitation the rights to use, copy, modify, merge, publish, - distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to - the following conditions: - . - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - . - 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 AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. diff --git a/distro/pkg/deb-noxdp/cz.nic.knotd.conf b/distro/pkg/deb-noxdp/cz.nic.knotd.conf deleted file mode 100644 index 50af87a..0000000 --- a/distro/pkg/deb-noxdp/cz.nic.knotd.conf +++ /dev/null @@ -1,9 +0,0 @@ -<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd"> -<busconfig> - <policy user="knot"> - <allow own="cz.nic.knotd" /> - </policy> - <policy context="default"> - <allow receive_sender="cz.nic.knotd" /> - </policy> -</busconfig> diff --git a/distro/pkg/deb-noxdp/docs b/distro/pkg/deb-noxdp/docs deleted file mode 100644 index b43bf86..0000000 --- a/distro/pkg/deb-noxdp/docs +++ /dev/null @@ -1 +0,0 @@ -README.md diff --git a/distro/pkg/deb-noxdp/knot-dnssecutils.install b/distro/pkg/deb-noxdp/knot-dnssecutils.install deleted file mode 100644 index 20009e8..0000000 --- a/distro/pkg/deb-noxdp/knot-dnssecutils.install +++ /dev/null @@ -1,3 +0,0 @@ -usr/bin/knsec3hash -usr/bin/kzonecheck -usr/bin/kzonesign diff --git a/distro/pkg/deb-noxdp/knot-dnssecutils.manpages b/distro/pkg/deb-noxdp/knot-dnssecutils.manpages deleted file mode 100644 index 913c4cb..0000000 --- a/distro/pkg/deb-noxdp/knot-dnssecutils.manpages +++ /dev/null @@ -1,3 +0,0 @@ -usr/share/man/man1/knsec3hash.1 -usr/share/man/man1/kzonecheck.1 -usr/share/man/man1/kzonesign.1 diff --git a/distro/pkg/deb-noxdp/knot-dnsutils.install b/distro/pkg/deb-noxdp/knot-dnsutils.install deleted file mode 100644 index 960fa92..0000000 --- a/distro/pkg/deb-noxdp/knot-dnsutils.install +++ /dev/null @@ -1,2 +0,0 @@ -usr/bin/kdig -usr/bin/knsupdate diff --git a/distro/pkg/deb-noxdp/knot-dnsutils.manpages b/distro/pkg/deb-noxdp/knot-dnsutils.manpages deleted file mode 100644 index 3cc29ec..0000000 --- a/distro/pkg/deb-noxdp/knot-dnsutils.manpages +++ /dev/null @@ -1,2 +0,0 @@ -usr/share/man/man1/kdig.1 -usr/share/man/man1/knsupdate.1 diff --git a/distro/pkg/deb-noxdp/knot-doc.install b/distro/pkg/deb-noxdp/knot-doc.install deleted file mode 100644 index c2a345d..0000000 --- a/distro/pkg/deb-noxdp/knot-doc.install +++ /dev/null @@ -1 +0,0 @@ -usr/share/doc/knot/* /usr/share/doc/knot-doc/ diff --git a/distro/pkg/deb-noxdp/knot-doc.links b/distro/pkg/deb-noxdp/knot-doc.links deleted file mode 100644 index 1376b3a..0000000 --- a/distro/pkg/deb-noxdp/knot-doc.links +++ /dev/null @@ -1,5 +0,0 @@ -usr/share/javascript/jquery/jquery.min.js usr/share/doc/knot-doc/_static/jquery.js -usr/share/javascript/sphinxdoc/1.0/doctools.js usr/share/doc/knot-doc/_static/doctools.js -usr/share/javascript/sphinxdoc/1.0/language_data.js usr/share/doc/knot-doc/_static/language_data.js -usr/share/javascript/sphinxdoc/1.0/searchtools.js usr/share/doc/knot-doc/_static/searchtools.js -usr/share/javascript/underscore/underscore.min.js usr/share/doc/knot-doc/_static/underscore.js diff --git a/distro/pkg/deb-noxdp/knot-exporter.install b/distro/pkg/deb-noxdp/knot-exporter.install deleted file mode 100644 index 4c2d5ed..0000000 --- a/distro/pkg/deb-noxdp/knot-exporter.install +++ /dev/null @@ -1,3 +0,0 @@ -usr/lib/python3*/dist-packages/knot_exporter-*.egg-info -usr/lib/python3*/dist-packages/knot_exporter/*.py -usr/bin/knot-exporter /usr/sbin/knot-exporter diff --git a/distro/pkg/deb-noxdp/knot-host.install b/distro/pkg/deb-noxdp/knot-host.install deleted file mode 100644 index 51bacf0..0000000 --- a/distro/pkg/deb-noxdp/knot-host.install +++ /dev/null @@ -1 +0,0 @@ -usr/bin/khost diff --git a/distro/pkg/deb-noxdp/knot-host.manpages b/distro/pkg/deb-noxdp/knot-host.manpages deleted file mode 100644 index 4891e2c..0000000 --- a/distro/pkg/deb-noxdp/knot-host.manpages +++ /dev/null @@ -1 +0,0 @@ -usr/share/man/man1/khost.1 diff --git a/distro/pkg/deb-noxdp/knot-module-dnstap.install b/distro/pkg/deb-noxdp/knot-module-dnstap.install deleted file mode 100644 index 983455e..0000000 --- a/distro/pkg/deb-noxdp/knot-module-dnstap.install +++ /dev/null @@ -1 +0,0 @@ -usr/lib/*/knot/modules-*/dnstap.so diff --git a/distro/pkg/deb-noxdp/knot-module-geoip.install b/distro/pkg/deb-noxdp/knot-module-geoip.install deleted file mode 100644 index 16d87c3..0000000 --- a/distro/pkg/deb-noxdp/knot-module-geoip.install +++ /dev/null @@ -1 +0,0 @@ -usr/lib/*/knot/modules-*/geoip.so diff --git a/distro/pkg/deb-noxdp/knot.dirs b/distro/pkg/deb-noxdp/knot.dirs deleted file mode 100644 index 6e937aa..0000000 --- a/distro/pkg/deb-noxdp/knot.dirs +++ /dev/null @@ -1 +0,0 @@ -var/lib/knot diff --git a/distro/pkg/deb-noxdp/knot.init b/distro/pkg/deb-noxdp/knot.init deleted file mode 100644 index 3f8fcae..0000000 --- a/distro/pkg/deb-noxdp/knot.init +++ /dev/null @@ -1,149 +0,0 @@ -#!/bin/sh -### BEGIN INIT INFO -# Provides: knot -# Required-Start: $network $local_fs $remote_fs $syslog -# Required-Stop: $remote_fs $syslog -# Default-Start: 2 3 4 5 -# Default-Stop: 0 1 6 -# Short-Description: authoritative domain name server -# Description: Knot DNS is a authoritative-only domain name server -### END INIT INFO - -# Author: Ondřej Surý <ondrej@debian.org> - -# PATH should only include /usr/* if it runs after the mountnfs.sh script -PATH=/sbin:/usr/sbin:/bin:/usr/bin -DESC="Knot DNS server" # Introduce a short description here -NAME=knotd # Introduce the short server's name here -DAEMON=/usr/sbin/$NAME # Introduce the server's location here -PIDFILE=/run/knot/knot.pid -SCRIPTNAME=/etc/init.d/knot -KNOTC=/usr/sbin/knotc -RUNDIR=/run/knot - -# Exit if the package is not installed -[ -x $DAEMON ] || exit 0 - -KNOTD_ARGS="" - -# Read configuration variable file if it is present -[ -r /etc/default/knot ] && . /etc/default/knot - -DAEMON_ARGS="-d $KNOTD_ARGS" - -# Define LSB log_* functions. -# Depend on sysvinit-utils (>= 2.96) to ensure that this file is present. -. /lib/lsb/init-functions - -# -# Function that starts the daemon/service -# -do_start() -{ - # Return - # 0 if daemon has been started - # 1 if daemon was already running - # 2 if daemon could not be started - - $KNOTC status >/dev/null 2>/dev/null \ - && return 1 - - start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --test > /dev/null \ - || return 1 - start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON -- \ - $DAEMON_ARGS \ - || return 2 -} - -# -# Function that stops the daemon/service -# -do_stop() -{ - # Return - # 0 if daemon has been stopped - # 1 if daemon was already stopped - # 2 if daemon could not be stopped - # other if a failure occurred - - $KNOTC status >/dev/null 2>/dev/null \ - || return 1 - - $KNOTC stop >/dev/null - RETVAL="$?" - [ $? = 1 ] && return 2 - - # Many daemons don't delete their pidfiles when they exit. - rm -f $PIDFILE - return 0 -} - -do_reload() { - $KNOTC reload >/dev/null - return $? -} - -do_mkrundir() { - mkdir -p $RUNDIR - chmod 0755 $RUNDIR - chown knot:knot $RUNDIR -} - -case "$1" in - start) - do_mkrundir - log_daemon_msg "Starting $DESC " "$NAME" - do_start - case "$?" in - 0|1) log_end_msg 0 ;; - 2) log_end_msg 1 ;; - esac - ;; - stop) - log_daemon_msg "Stopping $DESC" "$NAME" - do_stop - case "$?" in - 0|1) log_end_msg 0 ;; - 2) log_end_msg 1 ;; - esac - ;; - status) - STATUS=$($KNOTC status 2>&1 >/dev/null) - RETVAL=$? - if [ $RETVAL = 0 ]; then - log_success_msg "$NAME is running" - else - log_failure_msg "$NAME is not running ($STATUS)" - fi - exit $RETVAL - ;; - reload|force-reload) - log_daemon_msg "Reloading $DESC" "$NAME" - do_reload - log_end_msg $? - ;; - restart) - log_daemon_msg "Restarting $DESC" "$NAME" - do_stop - case "$?" in - 0|1) - do_start - case "$?" in - 0) log_end_msg 0 ;; - 1) log_end_msg 1 ;; # Old process is still running - *) log_end_msg 1 ;; # Failed to start - esac - ;; - *) - # Failed to stop - log_end_msg 1 - ;; - esac - ;; - *) - echo "Usage: $SCRIPTNAME {start|stop|status|restart|reload|force-reload}" >&2 - exit 3 - ;; -esac - -: diff --git a/distro/pkg/deb-noxdp/knot.install b/distro/pkg/deb-noxdp/knot.install deleted file mode 100644 index 5c716fc..0000000 --- a/distro/pkg/deb-noxdp/knot.install +++ /dev/null @@ -1,8 +0,0 @@ -debian/cz.nic.knotd.conf usr/share/dbus-1/system.d/ -debian/ufw/knot etc/ufw/applications.d/ -etc/knot/knot.conf -usr/sbin/kcatalogprint -usr/sbin/keymgr -usr/sbin/kjournalprint -usr/sbin/knotc -usr/sbin/knotd diff --git a/distro/pkg/deb-noxdp/knot.manpages b/distro/pkg/deb-noxdp/knot.manpages deleted file mode 100644 index 5d23e9f..0000000 --- a/distro/pkg/deb-noxdp/knot.manpages +++ /dev/null @@ -1,6 +0,0 @@ -usr/share/man/man5/knot.conf.5 -usr/share/man/man8/kcatalogprint.8 -usr/share/man/man8/keymgr.8 -usr/share/man/man8/kjournalprint.8 -usr/share/man/man8/knotc.8 -usr/share/man/man8/knotd.8 diff --git a/distro/pkg/deb-noxdp/knot.postinst b/distro/pkg/deb-noxdp/knot.postinst deleted file mode 100644 index da747c8..0000000 --- a/distro/pkg/deb-noxdp/knot.postinst +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/sh -set -e - -if [ "$1" = "configure" ]; then - if ! getent passwd knot > /dev/null; then - adduser --quiet --system --group --no-create-home --home /var/lib/knot knot - fi - - dpkg-statoverride --list /var/lib/knot >/dev/null 2>&1 || dpkg-statoverride --update --add root knot 0770 /var/lib/knot - dpkg-statoverride --list /etc/knot/knot.conf >/dev/null 2>&1 || dpkg-statoverride --update --add root knot 0640 /etc/knot/knot.conf - dpkg-statoverride --list /etc/knot >/dev/null 2>&1 || dpkg-statoverride --update --add root knot 0750 /etc/knot -fi - -#DEBHELPER# - -exit 0 diff --git a/distro/pkg/deb-noxdp/knot.postrm b/distro/pkg/deb-noxdp/knot.postrm deleted file mode 100644 index 14b3d69..0000000 --- a/distro/pkg/deb-noxdp/knot.postrm +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/sh -set -e - -if test "$1" = "purge"; then - state_dir=/var/lib/knot - for db_name in "catalog" "confdb" "journal" "keys" "timers"; do - rm -rf $state_dir/$db_name >/dev/null 2>&1 || true - done - rmdir $state_dir >/dev/null 2>&1 || true - [ -e $state_dir/* ] && echo "Notice: there are still data in ${state_dir}, please check." - - dpkg-statoverride --remove /var/lib/knot >/dev/null 2>&1 || true - dpkg-statoverride --remove /etc/knot/knot.conf >/dev/null 2>&1 || true - dpkg-statoverride --remove /etc/knot >/dev/null 2>&1 || true - - deluser --quiet knot >/dev/null 2>&1 || true -fi - -#DEBHELPER# - -exit 0 diff --git a/distro/pkg/deb-noxdp/knot.service b/distro/pkg/deb-noxdp/knot.service deleted file mode 100644 index e6c13ed..0000000 --- a/distro/pkg/deb-noxdp/knot.service +++ /dev/null @@ -1,30 +0,0 @@ -[Unit] -Description=Knot DNS server -Wants=network-online.target -After=network-online.target -Documentation=man:knotd(8) man:knot.conf(5) man:knotc(8) - -[Service] -Type=notify -User=knot -Group=knot -CapabilityBoundingSet=CAP_NET_BIND_SERVICE CAP_SETPCAP -AmbientCapabilities=CAP_NET_BIND_SERVICE CAP_SETPCAP -ExecStartPre=/usr/sbin/knotc conf-check -ExecStart=/usr/sbin/knotd -m "$KNOT_CONF_MAX_SIZE" -ExecReload=/bin/kill -HUP $MAINPID -Restart=on-abort -LimitNOFILE=1048576 -TimeoutStopSec=300 -# Extend the systemd startup timeout by this value (seconds) for each zone -Environment="KNOT_ZONE_LOAD_TIMEOUT_SEC=180" -# Maximum size (MiB) of a configuration database -Environment="KNOT_CONF_MAX_SIZE=512" - -# Expected systemd >= v239 -RuntimeDirectory=knot -StateDirectory=knot -NoNewPrivileges=yes - -[Install] -WantedBy=multi-user.target diff --git a/distro/pkg/deb-noxdp/libdnssec9.install b/distro/pkg/deb-noxdp/libdnssec9.install deleted file mode 100644 index 17a9fe6..0000000 --- a/distro/pkg/deb-noxdp/libdnssec9.install +++ /dev/null @@ -1 +0,0 @@ -usr/lib/*/libdnssec.so.* diff --git a/distro/pkg/deb-noxdp/libdnssec9.symbols b/distro/pkg/deb-noxdp/libdnssec9.symbols deleted file mode 100644 index c3ab2ed..0000000 --- a/distro/pkg/deb-noxdp/libdnssec9.symbols +++ /dev/null @@ -1,96 +0,0 @@ -libdnssec.so.9 libdnssec9 #MINVER# -* Build-Depends-Package: libknot-dev - dnssec_algorithm_digest_support@Base 3.2.0 - dnssec_algorithm_key_size_check@Base 3.2.0 - dnssec_algorithm_key_size_default@Base 3.2.0 - dnssec_algorithm_key_size_range@Base 3.2.0 - dnssec_algorithm_key_support@Base 3.2.0 - dnssec_algorithm_reproducible@Base 3.2.0 - dnssec_binary_alloc@Base 3.2.0 - dnssec_binary_cmp@Base 3.2.0 - dnssec_binary_dup@Base 3.2.0 - dnssec_binary_free@Base 3.2.0 - dnssec_binary_from_base64@Base 3.2.0 - dnssec_binary_resize@Base 3.2.0 - dnssec_binary_to_base64@Base 3.2.0 - dnssec_crypto_cleanup@Base 3.2.0 - dnssec_crypto_init@Base 3.2.0 - dnssec_crypto_reinit@Base 3.2.0 - dnssec_digest@Base 3.2.0 - dnssec_digest_finish@Base 3.2.0 - dnssec_digest_init@Base 3.2.0 - dnssec_key_can_sign@Base 3.2.0 - dnssec_key_can_verify@Base 3.2.0 - dnssec_key_clear@Base 3.2.0 - dnssec_key_create_ds@Base 3.2.0 - dnssec_key_dup@Base 3.2.0 - dnssec_key_free@Base 3.2.0 - dnssec_key_get_algorithm@Base 3.2.0 - dnssec_key_get_dname@Base 3.2.0 - dnssec_key_get_flags@Base 3.2.0 - dnssec_key_get_keyid@Base 3.2.0 - dnssec_key_get_keytag@Base 3.2.0 - dnssec_key_get_protocol@Base 3.2.0 - dnssec_key_get_pubkey@Base 3.2.0 - dnssec_key_get_rdata@Base 3.2.0 - dnssec_key_get_size@Base 3.2.0 - dnssec_key_load_pkcs8@Base 3.2.0 - dnssec_key_new@Base 3.2.0 - dnssec_key_set_algorithm@Base 3.2.0 - dnssec_key_set_dname@Base 3.2.0 - dnssec_key_set_flags@Base 3.2.0 - dnssec_key_set_protocol@Base 3.2.0 - dnssec_key_set_pubkey@Base 3.2.0 - dnssec_key_set_rdata@Base 3.2.0 - dnssec_keyid_copy@Base 3.2.0 - dnssec_keyid_equal@Base 3.2.0 - dnssec_keyid_is_valid@Base 3.2.0 - dnssec_keyid_normalize@Base 3.2.0 - dnssec_keystore_close@Base 3.2.0 - dnssec_keystore_deinit@Base 3.2.0 - dnssec_keystore_generate@Base 3.2.0 - dnssec_keystore_get_private@Base 3.2.0 - dnssec_keystore_import@Base 3.2.0 - dnssec_keystore_init@Base 3.2.0 - dnssec_keystore_init_pkcs11@Base 3.2.0 - dnssec_keystore_init_pkcs8@Base 3.2.0 - dnssec_keystore_open@Base 3.2.0 - dnssec_keystore_remove@Base 3.2.0 - dnssec_keystore_set_private@Base 3.2.0 - dnssec_keytag@Base 3.2.0 - dnssec_nsec3_hash@Base 3.2.0 - dnssec_nsec3_hash_length@Base 3.2.0 - dnssec_nsec3_params_free@Base 3.2.0 - dnssec_nsec3_params_from_rdata@Base 3.2.0 - dnssec_nsec3_params_match@Base 3.2.0 - dnssec_nsec_bitmap_add@Base 3.2.0 - dnssec_nsec_bitmap_clear@Base 3.2.0 - dnssec_nsec_bitmap_contains@Base 3.2.0 - dnssec_nsec_bitmap_free@Base 3.2.0 - dnssec_nsec_bitmap_new@Base 3.2.0 - dnssec_nsec_bitmap_size@Base 3.2.0 - dnssec_nsec_bitmap_write@Base 3.2.0 - dnssec_pem_from_privkey@Base 3.2.0 - dnssec_pem_from_x509@Base 3.2.0 - dnssec_pem_to_privkey@Base 3.2.0 - dnssec_pem_to_x509@Base 3.2.0 - dnssec_random_binary@Base 3.2.0 - dnssec_random_buffer@Base 3.2.0 - dnssec_sign_add@Base 3.2.0 - dnssec_sign_free@Base 3.2.0 - dnssec_sign_init@Base 3.2.0 - dnssec_sign_new@Base 3.2.0 - dnssec_sign_verify@Base 3.2.0 - dnssec_sign_write@Base 3.2.0 - dnssec_strerror@Base 3.2.0 - dnssec_tsig_add@Base 3.2.0 - dnssec_tsig_algorithm_from_dname@Base 3.2.0 - dnssec_tsig_algorithm_from_name@Base 3.2.0 - dnssec_tsig_algorithm_size@Base 3.2.0 - dnssec_tsig_algorithm_to_dname@Base 3.2.0 - dnssec_tsig_algorithm_to_name@Base 3.2.0 - dnssec_tsig_free@Base 3.2.0 - dnssec_tsig_new@Base 3.2.0 - dnssec_tsig_optimal_key_size@Base 3.2.0 - dnssec_tsig_size@Base 3.2.0 - dnssec_tsig_write@Base 3.2.0 diff --git a/distro/pkg/deb-noxdp/libknot-dev.install b/distro/pkg/deb-noxdp/libknot-dev.install deleted file mode 100644 index cb60d88..0000000 --- a/distro/pkg/deb-noxdp/libknot-dev.install +++ /dev/null @@ -1,3 +0,0 @@ -usr/include/ -usr/lib/*/*.so -usr/lib/*/pkgconfig/* diff --git a/distro/pkg/deb-noxdp/libknot14.symbols b/distro/pkg/deb-noxdp/libknot14.symbols deleted file mode 100644 index ba2024a..0000000 --- a/distro/pkg/deb-noxdp/libknot14.symbols +++ /dev/null @@ -1,226 +0,0 @@ -libknot.so.14 libknot14 #MINVER# - KNOT_DB_LMDB_DUPSORT@Base 3.3.0 - KNOT_DB_LMDB_INTEGERKEY@Base 3.3.0 - KNOT_DB_LMDB_MAPASYNC@Base 3.3.0 - KNOT_DB_LMDB_NOSYNC@Base 3.3.0 - KNOT_DB_LMDB_NOTLS@Base 3.3.0 - KNOT_DB_LMDB_RDONLY@Base 3.3.0 - KNOT_DB_LMDB_WRITEMAP@Base 3.3.0 - KNOT_DUMP_STYLE_DEFAULT@Base 3.3.0 - knot_ctl_accept@Base 3.3.0 - knot_ctl_alloc@Base 3.3.0 - knot_ctl_bind@Base 3.3.0 - knot_ctl_bind2@Base 3.3.6 - knot_ctl_close@Base 3.3.0 - knot_ctl_connect@Base 3.3.0 - knot_ctl_free@Base 3.3.0 - knot_ctl_receive@Base 3.3.0 - knot_ctl_send@Base 3.3.0 - knot_ctl_set_timeout@Base 3.3.0 - knot_ctl_unbind@Base 3.3.0 - knot_db_lmdb_api@Base 3.3.0 - knot_db_lmdb_del_exact@Base 3.3.0 - knot_db_lmdb_get_mapsize@Base 3.3.0 - knot_db_lmdb_get_path@Base 3.3.0 - knot_db_lmdb_get_usage@Base 3.3.0 - knot_db_lmdb_iter_del@Base 3.3.0 - knot_db_lmdb_txn_begin@Base 3.3.0 - knot_db_trie_api@Base 3.3.0 - knot_dname_cmp@Base 3.3.0 - knot_dname_copy@Base 3.3.0 - knot_dname_copy_lower@Base 3.3.0 - knot_dname_free@Base 3.3.0 - knot_dname_from_str@Base 3.3.0 - knot_dname_in_bailiwick@Base 3.3.0 - knot_dname_is_case_equal@Base 3.3.0 - knot_dname_is_equal@Base 3.3.0 - knot_dname_labels@Base 3.3.0 - knot_dname_lf@Base 3.3.0 - knot_dname_matched_labels@Base 3.3.0 - knot_dname_prefixlen@Base 3.3.0 - knot_dname_realsize@Base 3.3.0 - knot_dname_replace_suffix@Base 3.3.0 - knot_dname_size@Base 3.3.0 - knot_dname_store@Base 3.3.0 - knot_dname_to_lower@Base 3.3.0 - knot_dname_to_str@Base 3.3.0 - knot_dname_to_wire@Base 3.3.0 - knot_dname_unpack@Base 3.3.0 - knot_dname_wire_check@Base 3.3.0 - knot_dnssec_alg_names@Base 3.3.0 - knot_edns_add_option@Base 3.3.0 - knot_edns_alignment_size@Base 3.3.0 - knot_edns_chain_parse@Base 3.3.0 - knot_edns_chain_size@Base 3.3.0 - knot_edns_chain_write@Base 3.3.0 - knot_edns_client_subnet_get_addr@Base 3.3.0 - knot_edns_client_subnet_parse@Base 3.3.0 - knot_edns_client_subnet_set_addr@Base 3.3.0 - knot_edns_client_subnet_size@Base 3.3.0 - knot_edns_client_subnet_write@Base 3.3.0 - knot_edns_cookie_client_check@Base 3.3.0 - knot_edns_cookie_client_generate@Base 3.3.0 - knot_edns_cookie_parse@Base 3.3.0 - knot_edns_cookie_server_check@Base 3.3.0 - knot_edns_cookie_server_generate@Base 3.3.0 - knot_edns_cookie_size@Base 3.3.0 - knot_edns_cookie_write@Base 3.3.0 - knot_edns_ede_names@Base 3.3.0 - knot_edns_get_ext_rcode@Base 3.3.0 - knot_edns_get_option@Base 3.3.0 - knot_edns_get_options@Base 3.3.0 - knot_edns_get_version@Base 3.3.0 - knot_edns_init@Base 3.3.0 - knot_edns_keepalive_parse@Base 3.3.0 - knot_edns_keepalive_size@Base 3.3.0 - knot_edns_keepalive_write@Base 3.3.0 - knot_edns_opt_names@Base 3.3.0 - knot_edns_reserve_option@Base 3.3.0 - knot_edns_set_ext_rcode@Base 3.3.0 - knot_edns_set_version@Base 3.3.0 - knot_error_from_libdnssec@Base 3.3.0 - knot_get_obsolete_rdata_descriptor@Base 3.3.0 - knot_get_rdata_descriptor@Base 3.3.0 - knot_naptr_header_size@Base 3.3.0 - knot_opcode_names@Base 3.3.0 - knot_opt_code_to_string@Base 3.3.0 - knot_pkt_begin@Base 3.3.0 - knot_pkt_clear@Base 3.3.0 - knot_pkt_copy@Base 3.3.0 - knot_pkt_ext_rcode@Base 3.3.0 - knot_pkt_ext_rcode_name@Base 3.3.0 - knot_pkt_free@Base 3.3.0 - knot_pkt_init_response@Base 3.3.0 - knot_pkt_new@Base 3.3.0 - knot_pkt_parse@Base 3.3.0 - knot_pkt_parse_question@Base 3.3.0 - knot_pkt_put_question@Base 3.3.0 - knot_pkt_put_rotate@Base 3.3.0 - knot_pkt_reclaim@Base 3.3.0 - knot_pkt_reserve@Base 3.3.0 - knot_probe_alloc@Base 3.3.0 - knot_probe_consume@Base 3.3.0 - knot_probe_data_set@Base 3.3.0 - knot_probe_fd@Base 3.3.0 - knot_probe_free@Base 3.3.0 - knot_probe_produce@Base 3.3.0 - knot_probe_set_consumer@Base 3.3.0 - knot_probe_set_producer@Base 3.3.0 - knot_probe_tcp_rtt@Base 3.3.0 - knot_rcode_names@Base 3.3.0 - knot_rdataset_add@Base 3.3.0 - knot_rdataset_at@Base 3.3.0 - knot_rdataset_clear@Base 3.3.0 - knot_rdataset_copy@Base 3.3.0 - knot_rdataset_eq@Base 3.3.0 - knot_rdataset_intersect@Base 3.3.0 - knot_rdataset_intersect2@Base 3.3.0 - knot_rdataset_member@Base 3.3.0 - knot_rdataset_merge@Base 3.3.0 - knot_rdataset_subset@Base 3.3.0 - knot_rdataset_subtract@Base 3.3.0 - knot_rrclass_from_string@Base 3.3.0 - knot_rrclass_to_string@Base 3.3.0 - knot_rrset_add_rdata@Base 3.3.0 - knot_rrset_clear@Base 3.3.0 - knot_rrset_copy@Base 3.3.0 - knot_rrset_equal@Base 3.3.0 - knot_rrset_free@Base 3.3.0 - knot_rrset_is_nsec3rel@Base 3.3.0 - knot_rrset_new@Base 3.3.0 - knot_rrset_rr_from_wire@Base 3.3.0 - knot_rrset_rr_to_canonical@Base 3.3.0 - knot_rrset_size@Base 3.3.0 - knot_rrset_to_wire_extra@Base 3.3.0 - knot_rrset_txt_dump@Base 3.3.0 - knot_rrset_txt_dump_data@Base 3.3.0 - knot_rrset_txt_dump_edns@Base 3.3.0 - knot_rrset_txt_dump_header@Base 3.3.0 - knot_rrtype_additional_needed@Base 3.3.0 - knot_rrtype_from_string@Base 3.3.0 - knot_rrtype_is_dnssec@Base 3.3.0 - knot_rrtype_is_metatype@Base 3.3.0 - knot_rrtype_should_be_lowercased@Base 3.3.0 - knot_rrtype_to_string@Base 3.3.0 - knot_strerror@Base 3.3.0 - knot_svcb_param_names@Base 3.3.0 - knot_tcp_inbufs_upd@Base 3.3.0 - knot_tcp_outbufs_ack@Base 3.3.0 - knot_tcp_outbufs_add@Base 3.3.0 - knot_tcp_outbufs_can_send@Base 3.3.0 - knot_tcp_outbufs_usage@Base 3.3.0 - knot_tsig_add@Base 3.3.0 - knot_tsig_append@Base 3.3.0 - knot_tsig_client_check@Base 3.3.0 - knot_tsig_client_check_next@Base 3.3.0 - knot_tsig_create_rdata@Base 3.3.0 - knot_tsig_key_copy@Base 3.3.0 - knot_tsig_key_deinit@Base 3.3.0 - knot_tsig_key_init@Base 3.3.0 - knot_tsig_key_init_file@Base 3.3.0 - knot_tsig_key_init_str@Base 3.3.0 - knot_tsig_rcode_names@Base 3.3.0 - knot_tsig_rdata_alg@Base 3.3.0 - knot_tsig_rdata_alg_name@Base 3.3.0 - knot_tsig_rdata_error@Base 3.3.0 - knot_tsig_rdata_fudge@Base 3.3.0 - knot_tsig_rdata_is_ok@Base 3.3.0 - knot_tsig_rdata_mac@Base 3.3.0 - knot_tsig_rdata_mac_length@Base 3.3.0 - knot_tsig_rdata_orig_id@Base 3.3.0 - knot_tsig_rdata_other_data@Base 3.3.0 - knot_tsig_rdata_other_data_length@Base 3.3.0 - knot_tsig_rdata_set_fudge@Base 3.3.0 - knot_tsig_rdata_set_mac@Base 3.3.0 - knot_tsig_rdata_set_orig_id@Base 3.3.0 - knot_tsig_rdata_set_other_data@Base 3.3.0 - knot_tsig_rdata_set_time_signed@Base 3.3.0 - knot_tsig_rdata_time_signed@Base 3.3.0 - knot_tsig_rdata_tsig_timers_length@Base 3.3.0 - knot_tsig_rdata_tsig_variables_length@Base 3.3.0 - knot_tsig_server_check@Base 3.3.0 - knot_tsig_sign@Base 3.3.0 - knot_tsig_sign_next@Base 3.3.0 - knot_tsig_wire_maxsize@Base 3.3.0 - knot_tsig_wire_size@Base 3.3.0 - yp_addr@Base 3.3.0 - yp_addr_noport@Base 3.3.0 - yp_addr_noport_to_bin@Base 3.3.0 - yp_addr_noport_to_txt@Base 3.3.0 - yp_addr_range_to_bin@Base 3.3.0 - yp_addr_range_to_txt@Base 3.3.0 - yp_addr_to_bin@Base 3.3.0 - yp_addr_to_txt@Base 3.3.0 - yp_base64_to_bin@Base 3.3.0 - yp_base64_to_txt@Base 3.3.0 - yp_bool_to_bin@Base 3.3.0 - yp_bool_to_txt@Base 3.3.0 - yp_deinit@Base 3.3.0 - yp_dname_to_bin@Base 3.3.0 - yp_dname_to_txt@Base 3.3.0 - yp_format_id@Base 3.3.0 - yp_format_key0@Base 3.3.0 - yp_format_key1@Base 3.3.0 - yp_hex_to_bin@Base 3.3.0 - yp_hex_to_txt@Base 3.3.0 - yp_init@Base 3.3.0 - yp_int_to_bin@Base 3.3.0 - yp_int_to_txt@Base 3.3.0 - yp_item_to_bin@Base 3.3.0 - yp_item_to_txt@Base 3.3.0 - yp_option_to_bin@Base 3.3.0 - yp_option_to_txt@Base 3.3.0 - yp_parse@Base 3.3.0 - yp_schema_check_deinit@Base 3.3.0 - yp_schema_check_init@Base 3.3.0 - yp_schema_check_parser@Base 3.3.0 - yp_schema_check_str@Base 3.3.0 - yp_schema_copy@Base 3.3.0 - yp_schema_find@Base 3.3.0 - yp_schema_free@Base 3.3.0 - yp_schema_merge@Base 3.3.0 - yp_schema_purge_dynamic@Base 3.3.0 - yp_set_input_file@Base 3.3.0 - yp_set_input_string@Base 3.3.0 - yp_str_to_bin@Base 3.3.0 - yp_str_to_txt@Base 3.3.0 diff --git a/distro/pkg/deb-noxdp/libzscanner4.install b/distro/pkg/deb-noxdp/libzscanner4.install deleted file mode 100644 index a8dc226..0000000 --- a/distro/pkg/deb-noxdp/libzscanner4.install +++ /dev/null @@ -1 +0,0 @@ -usr/lib/*/libzscanner.so.* diff --git a/distro/pkg/deb-noxdp/libzscanner4.symbols b/distro/pkg/deb-noxdp/libzscanner4.symbols deleted file mode 100644 index 99ac3b7..0000000 --- a/distro/pkg/deb-noxdp/libzscanner4.symbols +++ /dev/null @@ -1,12 +0,0 @@ -libzscanner.so.4 libzscanner4 #MINVER# -* Build-Depends-Package: libknot-dev - zs_deinit@Base 3.1.0 - zs_errorname@Base 3.1.0 - zs_init@Base 3.1.0 - zs_parse_all@Base 3.1.0 - zs_parse_record@Base 3.1.0 - zs_set_input_file@Base 3.1.0 - zs_set_input_string@Base 3.1.0 - zs_set_processing@Base 3.1.0 - zs_set_processing_comment@Base 3.1.0 - zs_strerror@Base 3.1.0 diff --git a/distro/pkg/deb-noxdp/not-installed b/distro/pkg/deb-noxdp/not-installed deleted file mode 100644 index c928be1..0000000 --- a/distro/pkg/deb-noxdp/not-installed +++ /dev/null @@ -1 +0,0 @@ -etc/knot/example.com.zone diff --git a/distro/pkg/deb-noxdp/patches/05-revert-mod-dnstap-TCP-sink.patch b/distro/pkg/deb-noxdp/patches/05-revert-mod-dnstap-TCP-sink.patch deleted file mode 100644 index dae0fac..0000000 --- a/distro/pkg/deb-noxdp/patches/05-revert-mod-dnstap-TCP-sink.patch +++ /dev/null @@ -1,160 +0,0 @@ -From d236d2b7fcd5fa607f7bfd38044eb6f510fac7ce Mon Sep 17 00:00:00 2001 -From: Daniel Salzman <daniel.salzman@nic.cz> -Date: Wed, 12 Jun 2024 11:18:31 +0200 -Subject: [PATCH] Revert "mod-dnstap: add sink for TCP connection" - -This reverts commit 2ffd7dfa58ddcd1b860f0c9980fd082c3852d3e6. ---- - src/knot/modules/dnstap/dnstap.c | 74 +++++------------------------- - src/knot/modules/dnstap/dnstap.rst | 9 ++-- - 2 files changed, 15 insertions(+), 68 deletions(-) - -diff --git a/src/knot/modules/dnstap/dnstap.c b/src/knot/modules/dnstap/dnstap.c -index 612e48869..c8c82eaa4 100644 ---- a/src/knot/modules/dnstap/dnstap.c -+++ b/src/knot/modules/dnstap/dnstap.c -@@ -1,4 +1,4 @@ --/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> -+/* Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> - - 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 -@@ -185,33 +185,6 @@ finish: - return writer; - } - --static struct fstrm_writer* dnstap_tcp_writer(const char *address, const char *port) --{ -- struct fstrm_tcp_writer_options *opt = NULL; -- struct fstrm_writer_options *wopt = NULL; -- struct fstrm_writer *writer = NULL; -- -- opt = fstrm_tcp_writer_options_init(); -- if (opt == NULL) { -- goto finish; -- } -- -- fstrm_tcp_writer_options_set_socket_address(opt, address); -- fstrm_tcp_writer_options_set_socket_port(opt, port); -- -- wopt = fstrm_writer_options_init(); -- if (wopt == NULL) { -- goto finish; -- } -- fstrm_writer_options_add_content_type(wopt, DNSTAP_CONTENT_TYPE, -- strlen(DNSTAP_CONTENT_TYPE)); -- writer = fstrm_tcp_writer_init(opt, wopt); --finish: -- fstrm_tcp_writer_options_destroy(&opt); -- fstrm_writer_options_destroy(&wopt); -- return writer; --} -- - /*! \brief Create a basic file writer sink. */ - static struct fstrm_writer* dnstap_file_writer(const char *path) - { -@@ -240,42 +213,17 @@ finish: - } - - /*! \brief Create a log sink according to the path string. */ --static struct fstrm_writer* dnstap_writer(knotd_mod_t *mod, const char *path) -+static struct fstrm_writer* dnstap_writer(const char *path) - { -- const char *unix_prefix = "unix:"; -- const size_t unix_prefix_len = strlen(unix_prefix); -- -- const char *tcp_prefix = "tcp:"; -- const size_t tcp_prefix_len = strlen(tcp_prefix); -- -- const size_t path_len = strlen(path); -+ const char *prefix = "unix:"; -+ const size_t prefix_len = strlen(prefix); - - /* UNIX socket prefix. */ -- if (path_len > unix_prefix_len && -- strncmp(path, unix_prefix, unix_prefix_len) == 0) { -- knotd_mod_log(mod, LOG_DEBUG, "using sink UNIX socket '%s'", path); -- return dnstap_unix_writer(path + unix_prefix_len); -- /* TCP socket prefix. */ -- } else if (path_len > tcp_prefix_len && -- strncmp(path, tcp_prefix, tcp_prefix_len) == 0) { -- char addr[INET6_ADDRSTRLEN] = { 0 }; -- const char *delimiter = strchr(path + tcp_prefix_len, '@'); -- if (delimiter == NULL) { -- return NULL; -- } -- size_t addr_len = delimiter - path - tcp_prefix_len; -- if (addr_len >= sizeof(addr)) { -- return NULL; -- } -- memcpy(addr, path + tcp_prefix_len, addr_len); -- knotd_mod_log(mod, LOG_DEBUG, "using sink TCP address '%s' port '%s'", -- addr, delimiter + 1); -- return dnstap_tcp_writer(addr, delimiter + 1); -- /* File path. */ -- } else { -- knotd_mod_log(mod, LOG_DEBUG, "using sink file '%s'", path); -- return dnstap_file_writer(path); -+ if (strlen(path) > prefix_len && strncmp(path, prefix, prefix_len) == 0) { -+ return dnstap_unix_writer(path + prefix_len); - } -+ -+ return dnstap_file_writer(path); - } - - int dnstap_load(knotd_mod_t *mod) -@@ -325,7 +273,7 @@ int dnstap_load(knotd_mod_t *mod) - const bool log_responses = conf.single.boolean; - - /* Initialize the writer and the options. */ -- struct fstrm_writer *writer = dnstap_writer(mod, sink); -+ struct fstrm_writer *writer = dnstap_writer(sink); - if (writer == NULL) { - goto fail; - } -@@ -359,13 +307,13 @@ int dnstap_load(knotd_mod_t *mod) - - return KNOT_EOK; - fail: -- knotd_mod_log(mod, LOG_ERR, "failed to initialize sink '%s'", sink); -+ knotd_mod_log(mod, LOG_ERR, "failed to init sink '%s'", sink); - - free(ctx->identity); - free(ctx->version); - free(ctx); - -- return KNOT_EINVAL; -+ return KNOT_ENOMEM; - } - - void dnstap_unload(knotd_mod_t *mod) -diff --git a/src/knot/modules/dnstap/dnstap.rst b/src/knot/modules/dnstap/dnstap.rst -index 05eac09ab..358977da0 100644 ---- a/src/knot/modules/dnstap/dnstap.rst -+++ b/src/knot/modules/dnstap/dnstap.rst -@@ -11,7 +11,7 @@ Example - ------- - - The configuration comprises only a :ref:`mod-dnstap_sink` path parameter, --which can be either a file, a UNIX socket, or a TCP address:: -+which can be either a file or a UNIX socket:: - - mod-dnstap: - - id: capture_all -@@ -60,10 +60,9 @@ A module identifier. - sink - .... - --A sink path, which can be either a file, a UNIX socket when prefixed with --``unix:``, or a TCP `address@port` when prefixed with ``tcp:``. The file may --be specified as an absolute path or a path relative to --the :doc:`knotd<man_knotd>` startup directory. -+A sink path, which can be either a file or a UNIX socket when prefixed with -+``unix:``. The file may be specified as an absolute path or a path relative -+to the :doc:`knotd<man_knotd>` startup directory. - - *Required* - --- -2.34.1 - diff --git a/distro/pkg/deb-noxdp/patches/series b/distro/pkg/deb-noxdp/patches/series deleted file mode 100644 index 54de4e3..0000000 --- a/distro/pkg/deb-noxdp/patches/series +++ /dev/null @@ -1 +0,0 @@ -05-revert-mod-dnstap-TCP-sink.patch diff --git a/distro/pkg/deb-noxdp/prepare-environment b/distro/pkg/deb-noxdp/prepare-environment deleted file mode 100755 index 7176f5e..0000000 --- a/distro/pkg/deb-noxdp/prepare-environment +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/sh - -set -eu - -CONFFILE=${1:-/etc/knot/knot.conf} - -if [ ! -r $CONFFILE ]; then - echo "$CONFFILE doesn't exist or has wrong permissions." - exit 1; -fi - -KNOT_RUNDIR=$(sed -ne "s/#.*$//;s/.*rundir: \"*\([^\";]*\\).*/\\1/p;" $CONFFILE) -[ -z "$KNOT_RUNDIR" ] && KNOT_RUNDIR=/run/knot - -mkdir --parents "$KNOT_RUNDIR"; - -KNOT_USER=$(sed -ne "s/#.*$//;s/.*user:[ \"]*\\([^\\:\"]*\\)[ \"]*/\\1/p;" $CONFFILE) - -if [ -n "$KNOT_USER" ]; then - if ! getent passwd $KNOT_USER >/dev/null; then - echo "Configured user '$KNOT_USER' doesn't exist." - exit 1 - fi - - KNOT_GROUP=$(sed -ne "s/#.*$//;s/.*user:[ \"]*[^\\:\"]*\\:\\([^\"]*\\)[ \"]*/\\1/p;" $CONFFILE) - if [ -z "$KNOT_GROUP" ]; then - KNOT_GROUP=$(getent group $(getent passwd "$KNOT_USER" | cut -f 4 -d :) | cut -f 1 -d :) - fi - - if ! getent group $KNOT_GROUP >/dev/null; then - echo "Configured group '$KNOT_GROUP' doesn't exist." - exit 1 - fi - chown --silent "$KNOT_USER:$KNOT_GROUP" "$KNOT_RUNDIR" - chmod 775 "$KNOT_RUNDIR" -fi - -: diff --git a/distro/pkg/deb-noxdp/python3-libknot.install b/distro/pkg/deb-noxdp/python3-libknot.install deleted file mode 100644 index ce92dec..0000000 --- a/distro/pkg/deb-noxdp/python3-libknot.install +++ /dev/null @@ -1,2 +0,0 @@ -usr/lib/python3*/dist-packages/libknot-*.egg-info -usr/lib/python3*/dist-packages/libknot/*.py diff --git a/distro/pkg/deb-noxdp/rules b/distro/pkg/deb-noxdp/rules deleted file mode 100755 index 2372f70..0000000 --- a/distro/pkg/deb-noxdp/rules +++ /dev/null @@ -1,95 +0,0 @@ -#!/usr/bin/make -f - -export DEB_BUILD_MAINT_OPTIONS = hardening=+all -export DEB_CFLAGS_MAINT_APPEND = -Wall -DNDEBUG -export DEB_LDFLAGS_MAINT_APPEND = -Wl,--as-needed - -export DPKG_GENSYMBOLS_CHECK_LEVEL := 4 -export KNOT_SOFTHSM2_DSO = /usr/lib/softhsm/libsofthsm2.so - -include /usr/share/dpkg/default.mk - -ifeq (maint,$(filter $(DEB_BUILD_OPTIONS),maint)) - FASTPARSER := --disable-fastparser -else - FASTPARSER := --enable-fastparser -endif - -ifeq ($(DEB_HOST_ARCH),$(filter $(DEB_HOST_ARCH),hurd-i386)) - RECVMMSG:=--enable-recvmmsg=no -else - RECVMMSG:=--enable-recvmmsg=yes -endif - -ifeq ($(DEB_HOST_ARCH),$(filter $(DEB_HOST_ARCH),amd64 i386)) - RUN_TEST := -else - RUN_TEST := -timeout --kill-after=5s 5m -endif - -LIBKNOT_SYMBOLS := $(wildcard $(CURDIR)/debian/libknot*.symbols) - -# MAJOR.MINOR version part -BASE_VERSION := $(shell echo $(DEB_VERSION) | sed 's/^\([^.]\+\.[^.]\+\).*/\1/') - -# pyproject is supported by knot but fails on second `pybuild --build` -# invocation due to bug in dh-python's plugin_pyproject.py wheel unpack -export PYBUILD_SYSTEM = distutils - - -%: - dh $@ \ - --exclude=.la --exclude=example.com.zone \ - --with python3 - -override_dh_auto_configure: - dh_auto_configure -- \ - --sysconfdir=/etc \ - --localstatedir=/var/lib \ - --libexecdir=/usr/lib/knot \ - --with-rundir=/run/knot \ - --with-moduledir=/usr/lib/$(DEB_HOST_MULTIARCH)/knot/modules-$(BASE_VERSION) \ - --with-storage=/var/lib/knot \ - --enable-systemd=auto \ - --enable-dnstap \ - --with-module-dnstap=shared \ - --with-module-geoip=shared \ - $(RECVMMSG) \ - $(FASTPARSER) \ - --disable-silent-rules \ - --disable-static - -override_dh_auto_configure-indep: - pybuild --dir python/libknot --configure - pybuild --dir python/knot_exporter --configure - -override_dh_auto_build-indep: - dh_auto_build -- html - pybuild --dir python/libknot --build - pybuild --dir python/knot_exporter --build - -override_dh_auto_install-arch: - dh_auto_install -- install - # rename knot.sample.conf to knot.conf - mv $(CURDIR)/debian/tmp/etc/knot/knot.sample.conf $(CURDIR)/debian/tmp/etc/knot/knot.conf - -override_dh_auto_install-indep: - dh_auto_install -- install-html - # rename knot.sample.conf to knot.conf - mv $(CURDIR)/debian/tmp/etc/knot/knot.sample.conf $(CURDIR)/debian/tmp/etc/knot/knot.conf - pybuild --dir python/libknot --install - pybuild --dir python/knot_exporter --install - rm -rf $(CURDIR)/debian/tmp/usr/lib/python*/dist-packages/libknot/__pycache__ - rm -rf $(CURDIR)/debian/tmp/usr/lib/python*/dist-packages/knot_exporter/__pycache__ - -override_dh_auto_test-indep: -override_dh_auto_test-arch: -ifeq (,$(filter nocheck,$(DEB_BUILD_OPTIONS))) - $(RUN_TEST) dh_auto_test -endif - -override_dh_missing: - dh_missing --fail-missing - -override_dh_installchangelogs: - dh_installchangelogs NEWS diff --git a/distro/pkg/deb-noxdp/source/format b/distro/pkg/deb-noxdp/source/format deleted file mode 100644 index 163aaf8..0000000 --- a/distro/pkg/deb-noxdp/source/format +++ /dev/null @@ -1 +0,0 @@ -3.0 (quilt) diff --git a/distro/pkg/deb-noxdp/tests/authoritative-server b/distro/pkg/deb-noxdp/tests/authoritative-server deleted file mode 100755 index 028dfbf..0000000 --- a/distro/pkg/deb-noxdp/tests/authoritative-server +++ /dev/null @@ -1,150 +0,0 @@ -#!/bin/bash - -# Author: Daniel Kahn Gillmor <dkg@fifthhorseman.net> -# 2018-11-02 -# License: GPLv3+ - -# error on exit -set -e -# for handling jobspecs: -set -m - -if [ -z "$AUTOPKGTEST_ARTIFACTS" ]; then - d="$(mktemp -d)" - remove="$d" -else - d="$AUTOPKGTEST_ARTIFACTS" -fi -ip="${TESTIP:-127.$(( $RANDOM % 256 )).$(( $RANDOM % 256 )).$(( $RANDOM % 256 ))}" -port="${PORT:-8123}" -knotc="${KNOTC:-/usr/sbin/knotc}" -knotd="${KNOTD:-/usr/sbin/knotd}" -keymgr="${KEYMGR:-/usr/sbin/keymgr}" -kdig="${KDIG:-$(command -v kdig)}" -kzonecheck="${KZONECHECK:-$(command -v kzonecheck)}" -test_address="${TEST_ADDRESS:-192.0.2.199}" - -declare -a knot_conf="--config=$d/knot.conf" -declare -a knot_args=("$knot_conf" --verbose) - -printf "%s + %s roundtrip tests\n------------\n workdir: %s\n IP addr: %s\n knot args: %s\n" "$knotd" "$kdig" "$d" "$ip" "${knot_args[*]}" - -section() { - printf "\n%s\n" "$1" - sed 's/./-/g' <<<"$1" -} - -cleanup () { - section "cleaning up" - find "$d" -ls - "${knotc}" "${knot_args[@]}" stop - wait %1 - tail -n +1 -v "$d"/*.err - if [ "$remove" ]; then - printf "\ncleaning up working directory %s\n" "$remove" - rm -rf "$remove" - fi -} -trap cleanup EXIT - -section "set up config file and zonefile" - -user=$(id -nu) -group=$(id -ng) -cat > "$d/knot.conf" <<EOF -server: - rundir: "$d" - listen: $ip@$port - user: $user:$group -database: - storage: "$d" -template: - - id: default - storage: "$d" - file: "%s.zone" -zone: - - domain: example.net - dnssec-signing: on -EOF - -cat > "$d/example.net.zone" <<EOF -@ 1D IN SOA a.ns hostmaster 2018103100 3h 15m 1w 1d -@ 1D IN NS a.ns.example.net. -@ 1D IN NS b.ns.example.net. -a.ns 1D IN A 192.0.2.1 -b.ns 1D IN A 192.0.2.2 -test 1D IN A $test_address -EOF - -find "$d" -maxdepth 1 -type f -print0 | xargs -0 tail -n +1 -v - -mkdir -p "${d}" - -section "kzonecheck'ing zonefile" -"${kzonecheck}" -v "$d/example.net.zone" - -section "launching knot" -"${knotd}" "${knot_args[@]}" 2> "$d/knotd.err" & - -# FIXME: this is an annoying poll -- would be better if we could be -# alerted when the daemon is done setting up the socket, but i don't -# want to "--daemonize" if i can avoid it because i want the shell to -# remain in direct supervision of all its processes -tried=0 -while [ $tried -lt 10 ] ; do - if "${knotc}" "${knot_args[@]}" status 2>&1; then - break; - fi - sleep 0.5 - tried=$(( $tried + 1 )) -done -if [ $tried -ge 10 ]; then - printf "failed to use %s\n" "${knotc}" >&2 - exit 1 -fi - -section "querying knot" -"${kdig}" -p "${port}" @"${ip}" -t A test.example.net test2.example.net -answer="$("${kdig}" +short -p "${port}" @"${ip}" -t A test.example.net)" -if ! [ "$answer" = "$test_address" ]; then - printf "test.example.net mismatch!\nexpected: %s\n got: %s\n" "$test_address" "$answer" >&2 - exit 1 -fi -answer2="$("${kdig}" +short -p "${port}" @"${ip}" -t A test2.example.net)" -if ! [ "$answer2" = "" ]; then - printf "test2.example.net gave unexpected answer!\n got: %s\n" "$answer2" >&2 - exit 1 -fi - -section "modifying zone" -printf "test2 1D IN A $test_address\n" >>"$d/example.net.zone" -sed -i 's/^@ 1D IN SOA.*/@ 1D IN SOA a.ns hostmaster 2018110100 3h 15m 1w 1d/' "$d/example.net.zone" -"${knotc}" "${knot_args[@]}" reload -sleep 1 - -section "querying again" -"${kdig}" -p "${port}" @"${ip}" -t A test.example.net test2.example.net -answer="$("${kdig}" +short -p "${port}" @"${ip}" -t A test.example.net)" -if ! [ "$answer" = "$test_address" ]; then - printf "test.example.net mismatch!\nexpected: %s\n got: %s\n" "$test_address" "$answer" >&2 - exit 1 -fi -answer2="$("${kdig}" +short -p "${port}" @"${ip}" -t A test2.example.net)" -if ! [ "$answer2" = "$test_address" ]; then - printf "test2.example.net mismatch!\nexpected: %s\n got: %s\n" "$test_address" "$answer2" >&2 - exit 1 -fi - -section "querying DNSSEC" -"${kdig}" -p "${port}" @"${ip}" -t DNSKEY example.net. +dnssec -if ! "${kdig}" -p "${port}" @"${ip}" -t DNSKEY example.net. +dnssec 2>&1 | grep -q "RRSIG[[:space:]]*DNSKEY"; then - printf "DNSSEC query not successful" >&2 - exit 1 -fi - -section "listing keys with keymgr" -"${keymgr}" "$knot_conf" -e example.net. list -if ! "${keymgr}" "$knot_conf" -e example.net. list 2>&1 | grep -q "ksk=yes"; then - printf "keymgr did not list KSK as expected" >&2 - exit 1 -fi diff --git a/distro/pkg/deb-noxdp/tests/control b/distro/pkg/deb-noxdp/tests/control deleted file mode 100644 index e8b3dcb..0000000 --- a/distro/pkg/deb-noxdp/tests/control +++ /dev/null @@ -1,13 +0,0 @@ -Tests: kdig -Restrictions: skippable -Depends: - ca-certificates, - iputils-ping, - knot-dnsutils, - -Tests: authoritative-server -Depends: - findutils, - knot, - knot-dnsutils, - knot-dnssecutils, diff --git a/distro/pkg/deb-noxdp/tests/kdig b/distro/pkg/deb-noxdp/tests/kdig deleted file mode 100755 index f1dbe5a..0000000 --- a/distro/pkg/deb-noxdp/tests/kdig +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/bash - -set -e - -# Skip the test if no internet access -ping -c1 1.1.1.1 2>&1 || exit 77 - -expected=198.41.0.4 -answer=$(kdig +short +tls-ca @1.1.1.1 -q a.root-servers.net. -t A 2>&1 || true) - -if [ "$answer" != "$expected" ]; then - printf "expected: %s\ngot: %s\n" "$expected" "$answer" >&2 - kdig -d +tls-ca @1.1.1.1 -q a.root-servers.net. -t A -fi diff --git a/distro/pkg/deb-noxdp/ufw/knot b/distro/pkg/deb-noxdp/ufw/knot deleted file mode 100644 index ee36916..0000000 --- a/distro/pkg/deb-noxdp/ufw/knot +++ /dev/null @@ -1,4 +0,0 @@ -[Knot] -title=Internet Domain Name Server -description=The Knot DNS implements an Internet domain name server. -ports=53 diff --git a/distro/pkg/deb-noxdp/watch b/distro/pkg/deb-noxdp/watch deleted file mode 100644 index 7cf9ea1..0000000 --- a/distro/pkg/deb-noxdp/watch +++ /dev/null @@ -1,4 +0,0 @@ -version=4 -opts=uversionmangle=s/-((alpha|beta|rc)\d*)$/~$1/,pgpsigurlmangle=s/$/.asc/,dversionmangle=s/\+hotfix// \ -https://secure.nic.cz/files/knot-dns/ \ -(?:|.*/)knot(?:[_\-]v?|)(\d\S*)\.(?:tar\.xz|txz|tar\.bz2|tbz2|tar\.gz|tgz) diff --git a/distro/pkg/deb/control b/distro/pkg/deb/control index 5df1b62..b98dc4a 100644 --- a/distro/pkg/deb/control +++ b/distro/pkg/deb/control @@ -45,7 +45,7 @@ Architecture: any Depends: adduser, libdnssec9 (= ${binary:Version}), - libknot14 (= ${binary:Version}), + libknot15 (= ${binary:Version}), libzscanner4 (= ${binary:Version}), ${misc:Depends}, ${shlibs:Depends}, @@ -61,7 +61,7 @@ Description: Authoritative domain name server registry and hence is well suited to run anything from the root zone, the top-level domain, to many smaller standard domain names. -Package: libknot14 +Package: libknot15 Architecture: any Depends: ${misc:Depends}, @@ -117,7 +117,7 @@ Architecture: any Depends: libdnssec9 (= ${binary:Version}), libgnutls28-dev, - libknot14 (= ${binary:Version}), + libknot15 (= ${binary:Version}), libzscanner4 (= ${binary:Version}), ${misc:Depends}, Section: libdevel @@ -135,7 +135,7 @@ Package: knot-dnsutils Architecture: any Depends: libdnssec9 (= ${binary:Version}), - libknot14 (= ${binary:Version}), + libknot15 (= ${binary:Version}), libzscanner4 (= ${binary:Version}), ${misc:Depends}, ${shlibs:Depends}, @@ -162,7 +162,7 @@ Package: knot-dnssecutils Architecture: any Depends: libdnssec9 (= ${binary:Version}), - libknot14 (= ${binary:Version}), + libknot15 (= ${binary:Version}), libzscanner4 (= ${binary:Version}), ${misc:Depends}, ${shlibs:Depends}, @@ -184,7 +184,7 @@ Package: knot-host Architecture: any Depends: libdnssec9 (= ${binary:Version}), - libknot14 (= ${binary:Version}), + libknot15 (= ${binary:Version}), libzscanner4 (= ${binary:Version}), ${misc:Depends}, ${shlibs:Depends}, @@ -270,7 +270,7 @@ Description: Prometheus exporter for Knot DNS Package: python3-libknot Architecture: all Depends: - libknot14 (= ${binary:Version}), + libknot15 (= ${binary:Version}), ${misc:Depends}, ${python3:Depends}, Section: python diff --git a/distro/pkg/deb/knot.install b/distro/pkg/deb/knot.install index 5c716fc..a31224f 100644 --- a/distro/pkg/deb/knot.install +++ b/distro/pkg/deb/knot.install @@ -1,5 +1,4 @@ debian/cz.nic.knotd.conf usr/share/dbus-1/system.d/ -debian/ufw/knot etc/ufw/applications.d/ etc/knot/knot.conf usr/sbin/kcatalogprint usr/sbin/keymgr diff --git a/distro/pkg/deb/libknot14.install b/distro/pkg/deb/libknot14.install deleted file mode 100644 index f9b9f93..0000000 --- a/distro/pkg/deb/libknot14.install +++ /dev/null @@ -1 +0,0 @@ -usr/lib/*/libknot.so.* diff --git a/distro/pkg/deb/libknot14.symbols b/distro/pkg/deb/libknot14.symbols deleted file mode 100644 index 174d517..0000000 --- a/distro/pkg/deb/libknot14.symbols +++ /dev/null @@ -1,277 +0,0 @@ -libknot.so.14 libknot14 #MINVER# -* Build-Depends-Package: libknot-dev - KNOT_DB_LMDB_DUPSORT@Base 3.3.0 - KNOT_DB_LMDB_INTEGERKEY@Base 3.3.0 - KNOT_DB_LMDB_MAPASYNC@Base 3.3.0 - KNOT_DB_LMDB_NOSYNC@Base 3.3.0 - KNOT_DB_LMDB_NOTLS@Base 3.3.0 - KNOT_DB_LMDB_RDONLY@Base 3.3.0 - KNOT_DB_LMDB_WRITEMAP@Base 3.3.0 - KNOT_DUMP_STYLE_DEFAULT@Base 3.3.0 - knot_ctl_accept@Base 3.3.0 - knot_ctl_alloc@Base 3.3.0 - knot_ctl_bind@Base 3.3.0 - knot_ctl_bind2@Base 3.3.6 - knot_ctl_close@Base 3.3.0 - knot_ctl_connect@Base 3.3.0 - knot_ctl_free@Base 3.3.0 - knot_ctl_receive@Base 3.3.0 - knot_ctl_send@Base 3.3.0 - knot_ctl_set_timeout@Base 3.3.0 - knot_ctl_unbind@Base 3.3.0 - knot_db_lmdb_api@Base 3.3.0 - knot_db_lmdb_del_exact@Base 3.3.0 - knot_db_lmdb_get_mapsize@Base 3.3.0 - knot_db_lmdb_get_path@Base 3.3.0 - knot_db_lmdb_get_usage@Base 3.3.0 - knot_db_lmdb_iter_del@Base 3.3.0 - knot_db_lmdb_txn_begin@Base 3.3.0 - knot_db_trie_api@Base 3.3.0 - knot_dname_cmp@Base 3.3.0 - knot_dname_copy@Base 3.3.0 - knot_dname_copy_lower@Base 3.3.0 - knot_dname_free@Base 3.3.0 - knot_dname_from_str@Base 3.3.0 - knot_dname_in_bailiwick@Base 3.3.0 - knot_dname_is_case_equal@Base 3.3.0 - knot_dname_is_equal@Base 3.3.0 - knot_dname_labels@Base 3.3.0 - knot_dname_lf@Base 3.3.0 - knot_dname_matched_labels@Base 3.3.0 - knot_dname_prefixlen@Base 3.3.0 - knot_dname_realsize@Base 3.3.0 - knot_dname_replace_suffix@Base 3.3.0 - knot_dname_size@Base 3.3.0 - knot_dname_store@Base 3.3.0 - knot_dname_to_lower@Base 3.3.0 - knot_dname_to_str@Base 3.3.0 - knot_dname_to_wire@Base 3.3.0 - knot_dname_unpack@Base 3.3.0 - knot_dname_wire_check@Base 3.3.0 - knot_dnssec_alg_names@Base 3.3.0 - knot_edns_add_option@Base 3.3.0 - knot_edns_alignment_size@Base 3.3.0 - knot_edns_chain_parse@Base 3.3.0 - knot_edns_chain_size@Base 3.3.0 - knot_edns_chain_write@Base 3.3.0 - knot_edns_client_subnet_get_addr@Base 3.3.0 - knot_edns_client_subnet_parse@Base 3.3.0 - knot_edns_client_subnet_set_addr@Base 3.3.0 - knot_edns_client_subnet_size@Base 3.3.0 - knot_edns_client_subnet_write@Base 3.3.0 - knot_edns_cookie_client_check@Base 3.3.0 - knot_edns_cookie_client_generate@Base 3.3.0 - knot_edns_cookie_parse@Base 3.3.0 - knot_edns_cookie_server_check@Base 3.3.0 - knot_edns_cookie_server_generate@Base 3.3.0 - knot_edns_cookie_size@Base 3.3.0 - knot_edns_cookie_write@Base 3.3.0 - knot_edns_ede_names@Base 3.3.0 - knot_edns_get_ext_rcode@Base 3.3.0 - knot_edns_get_option@Base 3.3.0 - knot_edns_get_options@Base 3.3.0 - knot_edns_get_version@Base 3.3.0 - knot_edns_init@Base 3.3.0 - knot_edns_keepalive_parse@Base 3.3.0 - knot_edns_keepalive_size@Base 3.3.0 - knot_edns_keepalive_write@Base 3.3.0 - knot_edns_opt_names@Base 3.3.0 - knot_edns_reserve_option@Base 3.3.0 - knot_edns_set_ext_rcode@Base 3.3.0 - knot_edns_set_version@Base 3.3.0 - knot_error_from_libdnssec@Base 3.3.0 - knot_eth_mtu@Base 3.3.0 - knot_eth_name_from_addr@Base 3.3.0 - knot_eth_queues@Base 3.3.0 - knot_eth_rss@Base 3.3.0 - knot_eth_vlans@Base 3.3.0 - knot_eth_xdp_mode@Base 3.3.0 - knot_get_obsolete_rdata_descriptor@Base 3.3.0 - knot_get_rdata_descriptor@Base 3.3.0 - knot_naptr_header_size@Base 3.3.0 - knot_opcode_names@Base 3.3.0 - knot_opt_code_to_string@Base 3.3.0 - knot_pkt_begin@Base 3.3.0 - knot_pkt_clear@Base 3.3.0 - knot_pkt_copy@Base 3.3.0 - knot_pkt_ext_rcode@Base 3.3.0 - knot_pkt_ext_rcode_name@Base 3.3.0 - knot_pkt_free@Base 3.3.0 - knot_pkt_init_response@Base 3.3.0 - knot_pkt_new@Base 3.3.0 - knot_pkt_parse@Base 3.3.0 - knot_pkt_parse_question@Base 3.3.0 - knot_pkt_put_question@Base 3.3.0 - knot_pkt_put_rotate@Base 3.3.0 - knot_pkt_reclaim@Base 3.3.0 - knot_pkt_reserve@Base 3.3.0 - knot_probe_alloc@Base 3.3.0 - knot_probe_consume@Base 3.3.0 - knot_probe_data_set@Base 3.3.0 - knot_probe_fd@Base 3.3.0 - knot_probe_free@Base 3.3.0 - knot_probe_produce@Base 3.3.0 - knot_probe_set_consumer@Base 3.3.0 - knot_probe_set_producer@Base 3.3.0 - knot_probe_tcp_rtt@Base 3.3.0 - knot_quic_cleanup@Base 3.3.0 - knot_quic_client@Base 3.3.0 - knot_quic_conn_get_stream@Base 3.3.0 - knot_quic_conn_local_port@Base 3.3.0 - knot_quic_conn_new_stream@Base 3.3.0 - knot_quic_conn_next_timeout@Base 3.3.3 - knot_quic_conn_pin@Base 3.3.0 - knot_quic_conn_rtt@Base 3.3.0 - knot_quic_conn_stream_free@Base 3.3.0 - knot_quic_creds_cert@Base 3.3.0 - knot_quic_free_creds@Base 3.3.0 - knot_quic_handle@Base 3.3.0 - knot_quic_hanle_expiry@Base 3.3.3 - knot_quic_init_creds@Base 3.3.0 - knot_quic_init_creds_peer@Base 3.3.0 - knot_quic_send@Base 3.3.0 - knot_quic_session_available@Base 3.3.0 - knot_quic_session_load@Base 3.3.0 - knot_quic_session_save@Base 3.3.0 - knot_quic_stream_add_data@Base 3.3.0 - knot_quic_stream_get_process@Base 3.3.0 - knot_quic_table_free@Base 3.3.0 - knot_quic_table_new@Base 3.3.0 - knot_quic_table_rem@Base 3.3.0 - knot_quic_table_sweep@Base 3.3.0 - knot_rcode_names@Base 3.3.0 - knot_rdataset_add@Base 3.3.0 - knot_rdataset_at@Base 3.3.0 - knot_rdataset_clear@Base 3.3.0 - knot_rdataset_copy@Base 3.3.0 - knot_rdataset_eq@Base 3.3.0 - knot_rdataset_intersect@Base 3.3.0 - knot_rdataset_intersect2@Base 3.3.0 - knot_rdataset_member@Base 3.3.0 - knot_rdataset_merge@Base 3.3.0 - knot_rdataset_subset@Base 3.3.0 - knot_rdataset_subtract@Base 3.3.0 - knot_rrclass_from_string@Base 3.3.0 - knot_rrclass_to_string@Base 3.3.0 - knot_rrset_add_rdata@Base 3.3.0 - knot_rrset_clear@Base 3.3.0 - knot_rrset_copy@Base 3.3.0 - knot_rrset_equal@Base 3.3.0 - knot_rrset_free@Base 3.3.0 - knot_rrset_is_nsec3rel@Base 3.3.0 - knot_rrset_new@Base 3.3.0 - knot_rrset_rr_from_wire@Base 3.3.0 - knot_rrset_rr_to_canonical@Base 3.3.0 - knot_rrset_size@Base 3.3.0 - knot_rrset_to_wire_extra@Base 3.3.0 - knot_rrset_txt_dump@Base 3.3.0 - knot_rrset_txt_dump_data@Base 3.3.0 - knot_rrset_txt_dump_edns@Base 3.3.0 - knot_rrset_txt_dump_header@Base 3.3.0 - knot_rrtype_additional_needed@Base 3.3.0 - knot_rrtype_from_string@Base 3.3.0 - knot_rrtype_is_dnssec@Base 3.3.0 - knot_rrtype_is_metatype@Base 3.3.0 - knot_rrtype_should_be_lowercased@Base 3.3.0 - knot_rrtype_to_string@Base 3.3.0 - knot_strerror@Base 3.3.0 - knot_svcb_param_names@Base 3.3.0 - knot_tcp_cleanup@Base 3.3.0 - knot_tcp_inbufs_upd@Base 3.3.0 - knot_tcp_outbufs_ack@Base 3.3.0 - knot_tcp_outbufs_add@Base 3.3.0 - knot_tcp_outbufs_can_send@Base 3.3.0 - knot_tcp_outbufs_usage@Base 3.3.0 - knot_tcp_recv@Base 3.3.0 - knot_tcp_reply_data@Base 3.3.0 - knot_tcp_send@Base 3.3.0 - knot_tcp_sweep@Base 3.3.0 - knot_tcp_table_free@Base 3.3.0 - knot_tcp_table_new@Base 3.3.0 - knot_tsig_add@Base 3.3.0 - knot_tsig_append@Base 3.3.0 - knot_tsig_client_check@Base 3.3.0 - knot_tsig_client_check_next@Base 3.3.0 - knot_tsig_create_rdata@Base 3.3.0 - knot_tsig_key_copy@Base 3.3.0 - knot_tsig_key_deinit@Base 3.3.0 - knot_tsig_key_init@Base 3.3.0 - knot_tsig_key_init_file@Base 3.3.0 - knot_tsig_key_init_str@Base 3.3.0 - knot_tsig_rcode_names@Base 3.3.0 - knot_tsig_rdata_alg@Base 3.3.0 - knot_tsig_rdata_alg_name@Base 3.3.0 - knot_tsig_rdata_error@Base 3.3.0 - knot_tsig_rdata_fudge@Base 3.3.0 - knot_tsig_rdata_is_ok@Base 3.3.0 - knot_tsig_rdata_mac@Base 3.3.0 - knot_tsig_rdata_mac_length@Base 3.3.0 - knot_tsig_rdata_orig_id@Base 3.3.0 - knot_tsig_rdata_other_data@Base 3.3.0 - knot_tsig_rdata_other_data_length@Base 3.3.0 - knot_tsig_rdata_set_fudge@Base 3.3.0 - knot_tsig_rdata_set_mac@Base 3.3.0 - knot_tsig_rdata_set_orig_id@Base 3.3.0 - knot_tsig_rdata_set_other_data@Base 3.3.0 - knot_tsig_rdata_set_time_signed@Base 3.3.0 - knot_tsig_rdata_time_signed@Base 3.3.0 - knot_tsig_rdata_tsig_timers_length@Base 3.3.0 - knot_tsig_rdata_tsig_variables_length@Base 3.3.0 - knot_tsig_server_check@Base 3.3.0 - knot_tsig_sign@Base 3.3.0 - knot_tsig_sign_next@Base 3.3.0 - knot_tsig_wire_maxsize@Base 3.3.0 - knot_tsig_wire_size@Base 3.3.0 - knot_xdp_deinit@Base 3.3.0 - knot_xdp_init@Base 3.3.0 - knot_xdp_recv@Base 3.3.0 - knot_xdp_recv_finish@Base 3.3.0 - knot_xdp_reply_alloc@Base 3.3.0 - knot_xdp_send@Base 3.3.0 - knot_xdp_send_alloc@Base 3.3.0 - knot_xdp_send_finish@Base 3.3.0 - knot_xdp_send_free@Base 3.3.0 - knot_xdp_send_prepare@Base 3.3.0 - knot_xdp_socket_info@Base 3.3.0 - knot_xdp_socket_fd@Base 3.3.0 - yp_addr@Base 3.3.0 - yp_addr_noport@Base 3.3.0 - yp_addr_noport_to_bin@Base 3.3.0 - yp_addr_noport_to_txt@Base 3.3.0 - yp_addr_range_to_bin@Base 3.3.0 - yp_addr_range_to_txt@Base 3.3.0 - yp_addr_to_bin@Base 3.3.0 - yp_addr_to_txt@Base 3.3.0 - yp_base64_to_bin@Base 3.3.0 - yp_base64_to_txt@Base 3.3.0 - yp_bool_to_bin@Base 3.3.0 - yp_bool_to_txt@Base 3.3.0 - yp_deinit@Base 3.3.0 - yp_dname_to_bin@Base 3.3.0 - yp_dname_to_txt@Base 3.3.0 - yp_format_id@Base 3.3.0 - yp_format_key0@Base 3.3.0 - yp_format_key1@Base 3.3.0 - yp_hex_to_bin@Base 3.3.0 - yp_hex_to_txt@Base 3.3.0 - yp_init@Base 3.3.0 - yp_int_to_bin@Base 3.3.0 - yp_int_to_txt@Base 3.3.0 - yp_item_to_bin@Base 3.3.0 - yp_item_to_txt@Base 3.3.0 - yp_option_to_bin@Base 3.3.0 - yp_option_to_txt@Base 3.3.0 - yp_parse@Base 3.3.0 - yp_schema_check_deinit@Base 3.3.0 - yp_schema_check_init@Base 3.3.0 - yp_schema_check_parser@Base 3.3.0 - yp_schema_check_str@Base 3.3.0 - yp_schema_copy@Base 3.3.0 - yp_schema_find@Base 3.3.0 - yp_schema_free@Base 3.3.0 - yp_schema_merge@Base 3.3.0 - yp_schema_purge_dynamic@Base 3.3.0 - yp_set_input_file@Base 3.3.0 - yp_set_input_string@Base 3.3.0 - yp_str_to_bin@Base 3.3.0 - yp_str_to_txt@Base 3.3.0 diff --git a/distro/pkg/deb-noxdp/libknot14.install b/distro/pkg/deb/libknot15.install index f9b9f93..f9b9f93 100644 --- a/distro/pkg/deb-noxdp/libknot14.install +++ b/distro/pkg/deb/libknot15.install diff --git a/distro/pkg/deb/libknot15.symbols b/distro/pkg/deb/libknot15.symbols new file mode 100644 index 0000000..77dd5b0 --- /dev/null +++ b/distro/pkg/deb/libknot15.symbols @@ -0,0 +1,290 @@ +libknot.so.15 libknot15 #MINVER# +* Build-Depends-Package: libknot-dev + KNOT_DB_LMDB_DUPSORT@Base 3.4.0 + KNOT_DB_LMDB_INTEGERKEY@Base 3.4.0 + KNOT_DB_LMDB_MAPASYNC@Base 3.4.0 + KNOT_DB_LMDB_NOSYNC@Base 3.4.0 + KNOT_DB_LMDB_NOTLS@Base 3.4.0 + KNOT_DB_LMDB_RDONLY@Base 3.4.0 + KNOT_DB_LMDB_WRITEMAP@Base 3.4.0 + KNOT_DUMP_STYLE_DEFAULT@Base 3.4.0 + knot_creds_cert@Base 3.4.0 + knot_creds_free@Base 3.4.0 + knot_creds_init@Base 3.4.0 + knot_creds_init_peer@Base 3.4.0 + knot_creds_update@Base 3.4.0 + knot_ctl_accept@Base 3.4.0 + knot_ctl_alloc@Base 3.4.0 + knot_ctl_bind@Base 3.4.0 + knot_ctl_clone@Base 3.4.0 + knot_ctl_close@Base 3.4.0 + knot_ctl_connect@Base 3.4.0 + knot_ctl_free@Base 3.4.0 + knot_ctl_receive@Base 3.4.0 + knot_ctl_send@Base 3.4.0 + knot_ctl_set_timeout@Base 3.4.0 + knot_ctl_unbind@Base 3.4.0 + knot_db_lmdb_api@Base 3.4.0 + knot_db_lmdb_del_exact@Base 3.4.0 + knot_db_lmdb_get_mapsize@Base 3.4.0 + knot_db_lmdb_get_path@Base 3.4.0 + knot_db_lmdb_get_usage@Base 3.4.0 + knot_db_lmdb_iter_del@Base 3.4.0 + knot_db_lmdb_txn_begin@Base 3.4.0 + knot_db_trie_api@Base 3.4.0 + knot_dname_cmp@Base 3.4.0 + knot_dname_copy@Base 3.4.0 + knot_dname_copy_lower@Base 3.4.0 + knot_dname_free@Base 3.4.0 + knot_dname_from_str@Base 3.4.0 + knot_dname_in_bailiwick@Base 3.4.0 + knot_dname_is_case_equal@Base 3.4.0 + knot_dname_is_equal@Base 3.4.0 + knot_dname_labels@Base 3.4.0 + knot_dname_lf@Base 3.4.0 + knot_dname_matched_labels@Base 3.4.0 + knot_dname_prefixlen@Base 3.4.0 + knot_dname_realsize@Base 3.4.0 + knot_dname_replace_suffix@Base 3.4.0 + knot_dname_size@Base 3.4.0 + knot_dname_store@Base 3.4.0 + knot_dname_to_lower@Base 3.4.0 + knot_dname_to_str@Base 3.4.0 + knot_dname_to_wire@Base 3.4.0 + knot_dname_unpack@Base 3.4.0 + knot_dname_wire_check@Base 3.4.0 + knot_dnssec_alg_names@Base 3.4.0 + knot_edns_add_option@Base 3.4.0 + knot_edns_alignment_size@Base 3.4.0 + knot_edns_chain_parse@Base 3.4.0 + knot_edns_chain_size@Base 3.4.0 + knot_edns_chain_write@Base 3.4.0 + knot_edns_client_subnet_get_addr@Base 3.4.0 + knot_edns_client_subnet_parse@Base 3.4.0 + knot_edns_client_subnet_set_addr@Base 3.4.0 + knot_edns_client_subnet_size@Base 3.4.0 + knot_edns_client_subnet_write@Base 3.4.0 + knot_edns_cookie_client_check@Base 3.4.0 + knot_edns_cookie_client_generate@Base 3.4.0 + knot_edns_cookie_parse@Base 3.4.0 + knot_edns_cookie_server_check@Base 3.4.0 + knot_edns_cookie_server_generate@Base 3.4.0 + knot_edns_cookie_size@Base 3.4.0 + knot_edns_cookie_write@Base 3.4.0 + knot_edns_ede_names@Base 3.4.0 + knot_edns_get_ext_rcode@Base 3.4.0 + knot_edns_get_option@Base 3.4.0 + knot_edns_get_options@Base 3.4.0 + knot_edns_get_version@Base 3.4.0 + knot_edns_init@Base 3.4.0 + knot_edns_keepalive_parse@Base 3.4.0 + knot_edns_keepalive_size@Base 3.4.0 + knot_edns_keepalive_write@Base 3.4.0 + knot_edns_opt_names@Base 3.4.0 + knot_edns_reserve_option@Base 3.4.0 + knot_edns_set_ext_rcode@Base 3.4.0 + knot_edns_set_version@Base 3.4.0 + knot_error_from_libdnssec@Base 3.4.0 + knot_eth_mtu@Base 3.4.0 + knot_eth_name_from_addr@Base 3.4.0 + knot_eth_queues@Base 3.4.0 + knot_eth_rss@Base 3.4.0 + knot_eth_vlans@Base 3.4.0 + knot_eth_xdp_mode@Base 3.4.0 + knot_get_obsolete_rdata_descriptor@Base 3.4.0 + knot_get_rdata_descriptor@Base 3.4.0 + knot_naptr_header_size@Base 3.4.0 + knot_opcode_names@Base 3.4.0 + knot_opt_code_to_string@Base 3.4.0 + knot_pkt_begin@Base 3.4.0 + knot_pkt_clear@Base 3.4.0 + knot_pkt_copy@Base 3.4.0 + knot_pkt_ext_rcode@Base 3.4.0 + knot_pkt_ext_rcode_name@Base 3.4.0 + knot_pkt_free@Base 3.4.0 + knot_pkt_init_response@Base 3.4.0 + knot_pkt_new@Base 3.4.0 + knot_pkt_parse@Base 3.4.0 + knot_pkt_parse_question@Base 3.4.0 + knot_pkt_put_question@Base 3.4.0 + knot_pkt_put_rotate@Base 3.4.0 + knot_pkt_reclaim@Base 3.4.0 + knot_pkt_reserve@Base 3.4.0 + knot_probe_alloc@Base 3.4.0 + knot_probe_consume@Base 3.4.0 + knot_probe_data_set@Base 3.4.0 + knot_probe_fd@Base 3.4.0 + knot_probe_free@Base 3.4.0 + knot_probe_produce@Base 3.4.0 + knot_probe_set_consumer@Base 3.4.0 + knot_probe_set_producer@Base 3.4.0 + knot_probe_tcp_rtt@Base 3.4.0 + knot_quic_cleanup@Base 3.4.0 + knot_quic_client@Base 3.4.0 + knot_quic_conn_block@Base 3.4.0 + knot_quic_conn_get_stream@Base 3.4.0 + knot_quic_conn_local_port@Base 3.4.0 + knot_quic_conn_new_stream@Base 3.4.0 + knot_quic_conn_next_timeout@Base 3.4.0 + knot_quic_conn_rtt@Base 3.4.0 + knot_quic_conn_stream_free@Base 3.4.0 + knot_quic_handle@Base 3.4.0 + knot_quic_hanle_expiry@Base 3.4.0 + knot_quic_send@Base 3.4.0 + knot_quic_session_available@Base 3.4.0 + knot_quic_session_load@Base 3.4.0 + knot_quic_session_save@Base 3.4.0 + knot_quic_stream_add_data@Base 3.4.0 + knot_quic_stream_get_process@Base 3.4.0 + knot_quic_table_free@Base 3.4.0 + knot_quic_table_new@Base 3.4.0 + knot_quic_table_rem@Base 3.4.0 + knot_quic_table_sweep@Base 3.4.0 + knot_rcode_names@Base 3.4.0 + knot_rdataset_add@Base 3.4.0 + knot_rdataset_at@Base 3.4.0 + knot_rdataset_clear@Base 3.4.0 + knot_rdataset_copy@Base 3.4.0 + knot_rdataset_eq@Base 3.4.0 + knot_rdataset_intersect@Base 3.4.0 + knot_rdataset_intersect2@Base 3.4.0 + knot_rdataset_member@Base 3.4.0 + knot_rdataset_merge@Base 3.4.0 + knot_rdataset_subset@Base 3.4.0 + knot_rdataset_subtract@Base 3.4.0 + knot_rrclass_from_string@Base 3.4.0 + knot_rrclass_to_string@Base 3.4.0 + knot_rrset_add_rdata@Base 3.4.0 + knot_rrset_clear@Base 3.4.0 + knot_rrset_copy@Base 3.4.0 + knot_rrset_equal@Base 3.4.0 + knot_rrset_free@Base 3.4.0 + knot_rrset_is_nsec3rel@Base 3.4.0 + knot_rrset_new@Base 3.4.0 + knot_rrset_rr_from_wire@Base 3.4.0 + knot_rrset_rr_to_canonical@Base 3.4.0 + knot_rrset_size@Base 3.4.0 + knot_rrset_to_wire_extra@Base 3.4.0 + knot_rrset_txt_dump@Base 3.4.0 + knot_rrset_txt_dump_data@Base 3.4.0 + knot_rrset_txt_dump_edns@Base 3.4.0 + knot_rrset_txt_dump_header@Base 3.4.0 + knot_rrtype_additional_needed@Base 3.4.0 + knot_rrtype_from_string@Base 3.4.0 + knot_rrtype_is_dnssec@Base 3.4.0 + knot_rrtype_is_metatype@Base 3.4.0 + knot_rrtype_should_be_lowercased@Base 3.4.0 + knot_rrtype_to_string@Base 3.4.0 + knot_strerror@Base 3.4.0 + knot_svcb_param_names@Base 3.4.0 + knot_tcp_cleanup@Base 3.4.0 + knot_tcp_inbufs_upd@Base 3.4.0 + knot_tcp_outbufs_ack@Base 3.4.0 + knot_tcp_outbufs_add@Base 3.4.0 + knot_tcp_outbufs_can_send@Base 3.4.0 + knot_tcp_outbufs_usage@Base 3.4.0 + knot_tcp_recv@Base 3.4.0 + knot_tcp_reply_data@Base 3.4.0 + knot_tcp_send@Base 3.4.0 + knot_tcp_sweep@Base 3.4.0 + knot_tcp_table_free@Base 3.4.0 + knot_tcp_table_new@Base 3.4.0 + knot_tls_conn_block@Base 3.4.0 + knot_tls_conn_del@Base 3.4.0 + knot_tls_conn_new@Base 3.4.0 + knot_tls_ctx_free@Base 3.4.0 + knot_tls_ctx_new@Base 3.4.0 + knot_tls_handshake@Base 3.4.0 + knot_tls_pin@Base 3.4.0 + knot_tls_pin_check@Base 3.4.0 + knot_tls_recv_dns@Base 3.4.0 + knot_tls_send_dns@Base 3.4.0 + knot_tls_session@Base 3.4.0 + knot_tsig_add@Base 3.4.0 + knot_tsig_append@Base 3.4.0 + knot_tsig_client_check@Base 3.4.0 + knot_tsig_client_check_next@Base 3.4.0 + knot_tsig_create_rdata@Base 3.4.0 + knot_tsig_key_copy@Base 3.4.0 + knot_tsig_key_deinit@Base 3.4.0 + knot_tsig_key_init@Base 3.4.0 + knot_tsig_key_init_file@Base 3.4.0 + knot_tsig_key_init_str@Base 3.4.0 + knot_tsig_rcode_names@Base 3.4.0 + knot_tsig_rdata_alg@Base 3.4.0 + knot_tsig_rdata_alg_name@Base 3.4.0 + knot_tsig_rdata_error@Base 3.4.0 + knot_tsig_rdata_fudge@Base 3.4.0 + knot_tsig_rdata_is_ok@Base 3.4.0 + knot_tsig_rdata_mac@Base 3.4.0 + knot_tsig_rdata_mac_length@Base 3.4.0 + knot_tsig_rdata_orig_id@Base 3.4.0 + knot_tsig_rdata_other_data@Base 3.4.0 + knot_tsig_rdata_other_data_length@Base 3.4.0 + knot_tsig_rdata_set_fudge@Base 3.4.0 + knot_tsig_rdata_set_mac@Base 3.4.0 + knot_tsig_rdata_set_orig_id@Base 3.4.0 + knot_tsig_rdata_set_other_data@Base 3.4.0 + knot_tsig_rdata_set_time_signed@Base 3.4.0 + knot_tsig_rdata_time_signed@Base 3.4.0 + knot_tsig_rdata_tsig_timers_length@Base 3.4.0 + knot_tsig_rdata_tsig_variables_length@Base 3.4.0 + knot_tsig_server_check@Base 3.4.0 + knot_tsig_sign@Base 3.4.0 + knot_tsig_sign_next@Base 3.4.0 + knot_tsig_wire_maxsize@Base 3.4.0 + knot_tsig_wire_size@Base 3.4.0 + knot_xdp_deinit@Base 3.4.0 + knot_xdp_init@Base 3.4.0 + knot_xdp_recv@Base 3.4.0 + knot_xdp_recv_finish@Base 3.4.0 + knot_xdp_reply_alloc@Base 3.4.0 + knot_xdp_send@Base 3.4.0 + knot_xdp_send_alloc@Base 3.4.0 + knot_xdp_send_finish@Base 3.4.0 + knot_xdp_send_free@Base 3.4.0 + knot_xdp_send_prepare@Base 3.4.0 + knot_xdp_socket_info@Base 3.4.0 + knot_xdp_socket_stats@Base 3.4.0 + knot_xdp_socket_fd@Base 3.4.0 + yp_addr@Base 3.4.0 + yp_addr_noport@Base 3.4.0 + yp_addr_noport_to_bin@Base 3.4.0 + yp_addr_noport_to_txt@Base 3.4.0 + yp_addr_range_to_bin@Base 3.4.0 + yp_addr_range_to_txt@Base 3.4.0 + yp_addr_to_bin@Base 3.4.0 + yp_addr_to_txt@Base 3.4.0 + yp_base64_to_bin@Base 3.4.0 + yp_base64_to_txt@Base 3.4.0 + yp_bool_to_bin@Base 3.4.0 + yp_bool_to_txt@Base 3.4.0 + yp_deinit@Base 3.4.0 + yp_dname_to_bin@Base 3.4.0 + yp_dname_to_txt@Base 3.4.0 + yp_format_id@Base 3.4.0 + yp_format_key0@Base 3.4.0 + yp_format_key1@Base 3.4.0 + yp_hex_to_bin@Base 3.4.0 + yp_hex_to_txt@Base 3.4.0 + yp_init@Base 3.4.0 + yp_int_to_bin@Base 3.4.0 + yp_int_to_txt@Base 3.4.0 + yp_item_to_bin@Base 3.4.0 + yp_item_to_txt@Base 3.4.0 + yp_option_to_bin@Base 3.4.0 + yp_option_to_txt@Base 3.4.0 + yp_parse@Base 3.4.0 + yp_schema_check_deinit@Base 3.4.0 + yp_schema_check_init@Base 3.4.0 + yp_schema_check_parser@Base 3.4.0 + yp_schema_check_str@Base 3.4.0 + yp_schema_copy@Base 3.4.0 + yp_schema_find@Base 3.4.0 + yp_schema_free@Base 3.4.0 + yp_schema_merge@Base 3.4.0 + yp_schema_purge_dynamic@Base 3.4.0 + yp_set_input_file@Base 3.4.0 + yp_set_input_string@Base 3.4.0 + yp_str_to_bin@Base 3.4.0 + yp_str_to_txt@Base 3.4.0 diff --git a/distro/pkg/deb/rules b/distro/pkg/deb/rules index 82cc34b..c5c81d0 100755 --- a/distro/pkg/deb/rules +++ b/distro/pkg/deb/rules @@ -36,11 +36,9 @@ BASE_VERSION := $(shell echo $(DEB_VERSION) | sed 's/^\([^.]\+\.[^.]\+\).*/\1/') # invocation due to bug in dh-python's plugin_pyproject.py wheel unpack export PYBUILD_SYSTEM = distutils - %: dh $@ \ - --exclude=.la --exclude=example.com.zone \ - --with python3 + --with python3 override_dh_auto_configure: dh_auto_configure -- \ @@ -95,7 +93,7 @@ ifeq (,$(filter nocheck,$(DEB_BUILD_OPTIONS))) endif override_dh_missing: - dh_missing --fail-missing + dh_missing --exclude=.la --fail-missing override_dh_installchangelogs: dh_installchangelogs NEWS diff --git a/distro/pkg/deb/ufw/knot b/distro/pkg/deb/ufw/knot deleted file mode 100644 index ee36916..0000000 --- a/distro/pkg/deb/ufw/knot +++ /dev/null @@ -1,4 +0,0 @@ -[Knot] -title=Internet Domain Name Server -description=The Knot DNS implements an Internet domain name server. -ports=53 diff --git a/distro/pkg/el-7/01-revert-AC_PROG_CC.patch b/distro/pkg/el-7/01-revert-AC_PROG_CC.patch deleted file mode 100644 index fb49c00..0000000 --- a/distro/pkg/el-7/01-revert-AC_PROG_CC.patch +++ /dev/null @@ -1,18 +0,0 @@ -From: Daniel Salzman <daniel.salzman@nic.cz> -Date: Sun, 20 Feb 2022 20:38:35 +0100 -Subject: [PATCH] Revert "configure: upgrade from AC_PROG_CC_C99 to AC_PROG_CC" - -diff --git a/configure.ac b/configure.ac -index 6506197ed..c7df7f815 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -38,7 +38,8 @@ release_date=$($SED -n 's/^Knot DNS .* (\(.*\))/\1/p;q;' ${srcdir}/NEWS) - AC_SUBST([RELEASE_DATE], $release_date) - - # Set compiler compatibility flags --AC_PROG_CC -+AC_PROG_CC_C99 # AC_PROG_CC not supported by CentOS 7 -+AM_PROG_CC_C_O # Needed by CentOS 7 - AC_PROG_CPP_WERROR - - # Set default CFLAGS diff --git a/distro/pkg/el-7/02-fix-compilation-by-using-SHA-1.patch b/distro/pkg/el-7/02-fix-compilation-by-using-SHA-1.patch deleted file mode 100644 index cbc5aa2..0000000 --- a/distro/pkg/el-7/02-fix-compilation-by-using-SHA-1.patch +++ /dev/null @@ -1,67 +0,0 @@ -From: Daniel Salzman <daniel.salzman@nic.cz> -Date: Mon, 20 Mar 2023 14:57:54 +0100 -Subject: [PATCH] distro/el-7: fix compilation by using SHA-1 for PIN computation - -diff --git a/src/libknot/quic/quic.c b/src/libknot/quic/quic.c -index 5610865f6..555c495d9 100644 ---- a/src/libknot/quic/quic.c -+++ b/src/libknot/quic/quic.c -@@ -460,7 +460,7 @@ void knot_quic_conn_pin(knot_quic_conn_t *conn, uint8_t *pin, size_t *pin_size, - goto error; - } - -- ret = gnutls_x509_crt_get_key_id(cert, GNUTLS_KEYID_USE_SHA256, pin, pin_size); -+ ret = gnutls_x509_crt_get_key_id(cert, 0, pin, pin_size); - if (ret != GNUTLS_E_SUCCESS) { - gnutls_x509_crt_deinit(cert); - goto error; -diff --git a/src/utils/common/tls.c b/src/utils/common/tls.c -index 245dd3f96..6a2e7a986 100644 ---- a/src/utils/common/tls.c -+++ b/src/utils/common/tls.c -@@ -328,7 +328,7 @@ static int check_certificates(gnutls_session_t session, const list_t *pins) - - uint8_t cert_pin[CERT_PIN_LEN] = { 0 }; - size_t cert_pin_size = sizeof(cert_pin); -- ret = gnutls_x509_crt_get_key_id(cert, GNUTLS_KEYID_USE_SHA256, -+ ret = gnutls_x509_crt_get_key_id(cert, 0, - cert_pin, &cert_pin_size); - if (ret != 0) { - gnutls_x509_crt_deinit(cert); -@@ -336,18 +336,18 @@ static int check_certificates(gnutls_session_t session, const list_t *pins) - } - - // Check if correspond to a specified PIN. -- bool match = check_pin(cert_pin, sizeof(cert_pin), pins); -+ bool match = check_pin(cert_pin, cert_pin_size, pins); - if (match) { - matches++; - } - - uint8_t *txt_pin; -- ret = knot_base64_encode_alloc(cert_pin, sizeof(cert_pin), &txt_pin); -+ ret = knot_base64_encode_alloc(cert_pin, cert_pin_size, &txt_pin); - if (ret < 0) { - gnutls_x509_crt_deinit(cert); - return ret; - } -- DBG(" SHA-256 PIN: %.*s%s", ret, txt_pin, match ? ", MATCH" : ""); -+ DBG(" SHA-1 PIN: %.*s%s", ret, txt_pin, match ? ", MATCH" : ""); - free(txt_pin); - - gnutls_x509_crt_deinit(cert); -diff --git a/src/utils/kdig/kdig_params.c b/src/utils/kdig/kdig_params.c -index 359b8b596..8fd33b011 100644 ---- a/src/utils/kdig/kdig_params.c -+++ b/src/utils/kdig/kdig_params.c -@@ -707,8 +707,8 @@ static int opt_tls_pin(const char *arg, void *query) - if (ret < 0) { - ERR("invalid +tls-pin=%s", arg); - return ret; -- } else if (ret != CERT_PIN_LEN) { // Check for 256-bit value. -- ERR("invalid sha256 hash length +tls-pin=%s", arg); -+ } else if (ret != 20) { // Check for 256-bit value. -+ ERR("invalid sha1 hash length +tls-pin=%s", arg); - return KNOT_EINVAL; - } - diff --git a/distro/pkg/el-7/03-doc-don-t-try-to-import-sphinx_panels.patch b/distro/pkg/el-7/03-doc-don-t-try-to-import-sphinx_panels.patch deleted file mode 100644 index 8ef7e7e..0000000 --- a/distro/pkg/el-7/03-doc-don-t-try-to-import-sphinx_panels.patch +++ /dev/null @@ -1,25 +0,0 @@ -From c05abb0401d3343b96ced4a6cdd724ee04adfe1b Mon Sep 17 00:00:00 2001 -From: Daniel Salzman <daniel.salzman@nic.cz> -Date: Mon, 21 Aug 2023 16:54:46 +0200 -Subject: [PATCH] doc: don't try to import sphinx_panels on CentOS 7 - - - 1 file changed, 3 deletions(-) - -diff --git a/doc/conf.py b/doc/conf.py -index fc2e94d96..515241051 100644 ---- a/doc/conf.py -+++ b/doc/conf.py -@@ -27,9 +27,6 @@ sys.path.insert(0, os.path.abspath('ext')) - - # Add any Sphinx extension module names here, as strings. They can be extensions - # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. --import importlib.util --if importlib.util.find_spec("sphinx_panels"): -- extensions = [ 'sphinx_panels' ] - - # Add any paths that contain templates here, relative to this directory. - templates_path = ['_templates'] --- -2.25.1 - diff --git a/distro/pkg/el-7/04-revert-don-t-share-PKCS-11-private-keys.patch b/distro/pkg/el-7/04-revert-don-t-share-PKCS-11-private-keys.patch deleted file mode 100644 index d360433..0000000 --- a/distro/pkg/el-7/04-revert-don-t-share-PKCS-11-private-keys.patch +++ /dev/null @@ -1,160 +0,0 @@ -From 1bad8f831a9fd506516549ac7461f97c689a0c46 Mon Sep 17 00:00:00 2001 -From: Daniel Salzman <daniel.salzman@nic.cz> -Date: Mon, 11 Dec 2023 17:08:23 +0100 -Subject: [PATCH] Revert "zone-sign: don't share PKCS 11 private keys by - multiple signing threads" - -This reverts commit 7d63e8e0825e03b8e0608e87b86968c452755c93. ---- - src/knot/dnssec/zone-keys.c | 38 +++---------------------------------- - src/libdnssec/key.h | 4 ++-- - src/libdnssec/key/key.c | 24 +---------------------- - tests/libdnssec/test_key.c | 4 ++-- - 4 files changed, 8 insertions(+), 62 deletions(-) - -diff --git a/src/knot/dnssec/zone-keys.c b/src/knot/dnssec/zone-keys.c -index cd6bf0bb3..d5cccc759 100644 ---- a/src/knot/dnssec/zone-keys.c -+++ b/src/knot/dnssec/zone-keys.c -@@ -642,21 +642,6 @@ int zone_key_calculate_ds(zone_key_t *for_key, dnssec_key_digest_t digesttype, - return ret; - } - --static int dup_zone_key(const zone_key_t *src, zone_key_t *dst) --{ -- assert(src); -- assert(dst); -- -- *dst = *src; -- -- dst->key = dnssec_key_dup(src->key); -- if (dst->key == NULL) { -- return KNOT_ENOMEM; -- } -- -- return KNOT_EOK; --} -- - zone_sign_ctx_t *zone_sign_ctx(const zone_keyset_t *keyset, const kdnssec_ctx_t *dnssec_ctx) - { - zone_sign_ctx_t *ctx = calloc(1, sizeof(*ctx) + keyset->count * sizeof(*ctx->sign_ctxs)); -@@ -665,24 +650,11 @@ zone_sign_ctx_t *zone_sign_ctx(const zone_keyset_t *keyset, const kdnssec_ctx_t - } - - ctx->sign_ctxs = (dnssec_sign_ctx_t **)(ctx + 1); -- -- ctx->keys = calloc(keyset->count, sizeof(*ctx->keys)); -- if (ctx->keys == NULL) { -- zone_sign_ctx_free(ctx); -- return NULL; -- } - ctx->count = keyset->count; -- -+ ctx->keys = keyset->keys; - ctx->dnssec_ctx = dnssec_ctx; - for (size_t i = 0; i < ctx->count; i++) { -- // Clone the key to avoid thread contention on the key mutex. -- int ret = dup_zone_key(&keyset->keys[i], &ctx->keys[i]); -- if (ret != KNOT_EOK) { -- zone_sign_ctx_free(ctx); -- return NULL; -- } -- -- ret = dnssec_sign_new(&ctx->sign_ctxs[i], ctx->keys[i].key); -+ int ret = dnssec_sign_new(&ctx->sign_ctxs[i], ctx->keys[i].key); - if (ret != DNSSEC_EOK) { - zone_sign_ctx_free(ctx); - return NULL; -@@ -719,12 +691,8 @@ void zone_sign_ctx_free(zone_sign_ctx_t *ctx) - { - if (ctx != NULL) { - for (size_t i = 0; i < ctx->count; i++) { -- if (ctx->keys != NULL) { -- dnssec_key_free(ctx->keys[i].key); -- } - dnssec_sign_free(ctx->sign_ctxs[i]); - } -- free(ctx->keys); - free(ctx); - } - } -diff --git a/src/libdnssec/key.h b/src/libdnssec/key.h -index aa8002b4a..2a69d377f 100644 ---- a/src/libdnssec/key.h -+++ b/src/libdnssec/key.h -@@ -1,4 +1,4 @@ --/* Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> -+/* Copyright (C) 2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> - - 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 -@@ -134,7 +134,7 @@ void dnssec_key_free(dnssec_key_t *key); - /*! - * Create a copy of a DNSSEC key. - * -- * Public key isn't duplicated. -+ * Only a public part of the key is copied. - */ - dnssec_key_t *dnssec_key_dup(const dnssec_key_t *key); - -diff --git a/src/libdnssec/key/key.c b/src/libdnssec/key/key.c -index 4574bbefb..f36316712 100644 ---- a/src/libdnssec/key/key.c -+++ b/src/libdnssec/key/key.c -@@ -1,4 +1,4 @@ --/* Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> -+/* Copyright (C) 2019 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> - - 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 -@@ -141,28 +141,6 @@ dnssec_key_t *dnssec_key_dup(const dnssec_key_t *key) - return NULL; - } - -- if (key->private_key != NULL) { -- gnutls_privkey_init(&dup->private_key); -- -- gnutls_privkey_type_t type = gnutls_privkey_get_type(key->private_key); -- if (type == GNUTLS_PRIVKEY_PKCS11) { --#ifdef ENABLE_PKCS11 -- gnutls_pkcs11_privkey_t tmp; -- gnutls_privkey_export_pkcs11(key->private_key, &tmp); -- gnutls_privkey_import_pkcs11(dup->private_key, tmp, -- GNUTLS_PRIVKEY_IMPORT_AUTO_RELEASE); --#else -- assert(0); --#endif // ENABLE_PKCS11 -- } else { -- assert(type == GNUTLS_PRIVKEY_X509); -- gnutls_x509_privkey_t tmp; -- gnutls_privkey_export_x509(key->private_key, &tmp); -- gnutls_privkey_import_x509(dup->private_key, tmp, -- GNUTLS_PRIVKEY_IMPORT_AUTO_RELEASE); -- } -- } -- - return dup; - } - -diff --git a/tests/libdnssec/test_key.c b/tests/libdnssec/test_key.c -index c3643f08c..cd0aaee0e 100644 ---- a/tests/libdnssec/test_key.c -+++ b/tests/libdnssec/test_key.c -@@ -1,4 +1,4 @@ --/* Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> -+/* Copyright (C) 2021 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> - - 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 -@@ -148,7 +148,7 @@ static void test_private_key(const key_parameters_t *params) - - check_key_tag(copy, params); - check_key_size(copy, params); -- check_usage(copy, true, true); -+ check_usage(copy, true, false); - - dnssec_key_free(copy); - dnssec_key_free(key); --- -2.34.1 - diff --git a/distro/pkg/el-7/05-revert-mod-dnstap-TCP-sink.patch b/distro/pkg/el-7/05-revert-mod-dnstap-TCP-sink.patch deleted file mode 100644 index dae0fac..0000000 --- a/distro/pkg/el-7/05-revert-mod-dnstap-TCP-sink.patch +++ /dev/null @@ -1,160 +0,0 @@ -From d236d2b7fcd5fa607f7bfd38044eb6f510fac7ce Mon Sep 17 00:00:00 2001 -From: Daniel Salzman <daniel.salzman@nic.cz> -Date: Wed, 12 Jun 2024 11:18:31 +0200 -Subject: [PATCH] Revert "mod-dnstap: add sink for TCP connection" - -This reverts commit 2ffd7dfa58ddcd1b860f0c9980fd082c3852d3e6. ---- - src/knot/modules/dnstap/dnstap.c | 74 +++++------------------------- - src/knot/modules/dnstap/dnstap.rst | 9 ++-- - 2 files changed, 15 insertions(+), 68 deletions(-) - -diff --git a/src/knot/modules/dnstap/dnstap.c b/src/knot/modules/dnstap/dnstap.c -index 612e48869..c8c82eaa4 100644 ---- a/src/knot/modules/dnstap/dnstap.c -+++ b/src/knot/modules/dnstap/dnstap.c -@@ -1,4 +1,4 @@ --/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> -+/* Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> - - 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 -@@ -185,33 +185,6 @@ finish: - return writer; - } - --static struct fstrm_writer* dnstap_tcp_writer(const char *address, const char *port) --{ -- struct fstrm_tcp_writer_options *opt = NULL; -- struct fstrm_writer_options *wopt = NULL; -- struct fstrm_writer *writer = NULL; -- -- opt = fstrm_tcp_writer_options_init(); -- if (opt == NULL) { -- goto finish; -- } -- -- fstrm_tcp_writer_options_set_socket_address(opt, address); -- fstrm_tcp_writer_options_set_socket_port(opt, port); -- -- wopt = fstrm_writer_options_init(); -- if (wopt == NULL) { -- goto finish; -- } -- fstrm_writer_options_add_content_type(wopt, DNSTAP_CONTENT_TYPE, -- strlen(DNSTAP_CONTENT_TYPE)); -- writer = fstrm_tcp_writer_init(opt, wopt); --finish: -- fstrm_tcp_writer_options_destroy(&opt); -- fstrm_writer_options_destroy(&wopt); -- return writer; --} -- - /*! \brief Create a basic file writer sink. */ - static struct fstrm_writer* dnstap_file_writer(const char *path) - { -@@ -240,42 +213,17 @@ finish: - } - - /*! \brief Create a log sink according to the path string. */ --static struct fstrm_writer* dnstap_writer(knotd_mod_t *mod, const char *path) -+static struct fstrm_writer* dnstap_writer(const char *path) - { -- const char *unix_prefix = "unix:"; -- const size_t unix_prefix_len = strlen(unix_prefix); -- -- const char *tcp_prefix = "tcp:"; -- const size_t tcp_prefix_len = strlen(tcp_prefix); -- -- const size_t path_len = strlen(path); -+ const char *prefix = "unix:"; -+ const size_t prefix_len = strlen(prefix); - - /* UNIX socket prefix. */ -- if (path_len > unix_prefix_len && -- strncmp(path, unix_prefix, unix_prefix_len) == 0) { -- knotd_mod_log(mod, LOG_DEBUG, "using sink UNIX socket '%s'", path); -- return dnstap_unix_writer(path + unix_prefix_len); -- /* TCP socket prefix. */ -- } else if (path_len > tcp_prefix_len && -- strncmp(path, tcp_prefix, tcp_prefix_len) == 0) { -- char addr[INET6_ADDRSTRLEN] = { 0 }; -- const char *delimiter = strchr(path + tcp_prefix_len, '@'); -- if (delimiter == NULL) { -- return NULL; -- } -- size_t addr_len = delimiter - path - tcp_prefix_len; -- if (addr_len >= sizeof(addr)) { -- return NULL; -- } -- memcpy(addr, path + tcp_prefix_len, addr_len); -- knotd_mod_log(mod, LOG_DEBUG, "using sink TCP address '%s' port '%s'", -- addr, delimiter + 1); -- return dnstap_tcp_writer(addr, delimiter + 1); -- /* File path. */ -- } else { -- knotd_mod_log(mod, LOG_DEBUG, "using sink file '%s'", path); -- return dnstap_file_writer(path); -+ if (strlen(path) > prefix_len && strncmp(path, prefix, prefix_len) == 0) { -+ return dnstap_unix_writer(path + prefix_len); - } -+ -+ return dnstap_file_writer(path); - } - - int dnstap_load(knotd_mod_t *mod) -@@ -325,7 +273,7 @@ int dnstap_load(knotd_mod_t *mod) - const bool log_responses = conf.single.boolean; - - /* Initialize the writer and the options. */ -- struct fstrm_writer *writer = dnstap_writer(mod, sink); -+ struct fstrm_writer *writer = dnstap_writer(sink); - if (writer == NULL) { - goto fail; - } -@@ -359,13 +307,13 @@ int dnstap_load(knotd_mod_t *mod) - - return KNOT_EOK; - fail: -- knotd_mod_log(mod, LOG_ERR, "failed to initialize sink '%s'", sink); -+ knotd_mod_log(mod, LOG_ERR, "failed to init sink '%s'", sink); - - free(ctx->identity); - free(ctx->version); - free(ctx); - -- return KNOT_EINVAL; -+ return KNOT_ENOMEM; - } - - void dnstap_unload(knotd_mod_t *mod) -diff --git a/src/knot/modules/dnstap/dnstap.rst b/src/knot/modules/dnstap/dnstap.rst -index 05eac09ab..358977da0 100644 ---- a/src/knot/modules/dnstap/dnstap.rst -+++ b/src/knot/modules/dnstap/dnstap.rst -@@ -11,7 +11,7 @@ Example - ------- - - The configuration comprises only a :ref:`mod-dnstap_sink` path parameter, --which can be either a file, a UNIX socket, or a TCP address:: -+which can be either a file or a UNIX socket:: - - mod-dnstap: - - id: capture_all -@@ -60,10 +60,9 @@ A module identifier. - sink - .... - --A sink path, which can be either a file, a UNIX socket when prefixed with --``unix:``, or a TCP `address@port` when prefixed with ``tcp:``. The file may --be specified as an absolute path or a path relative to --the :doc:`knotd<man_knotd>` startup directory. -+A sink path, which can be either a file or a UNIX socket when prefixed with -+``unix:``. The file may be specified as an absolute path or a path relative -+to the :doc:`knotd<man_knotd>` startup directory. - - *Required* - --- -2.34.1 - diff --git a/distro/pkg/el-7/knot.service b/distro/pkg/el-7/knot.service deleted file mode 100644 index a872929..0000000 --- a/distro/pkg/el-7/knot.service +++ /dev/null @@ -1,25 +0,0 @@ -[Unit] -Description=Knot DNS server -Wants=network-online.target -After=network-online.target -Documentation=man:knotd(8) man:knot.conf(5) man:knotc(8) - -[Service] -Type=notify -User=knot -Group=knot -CapabilityBoundingSet=CAP_NET_BIND_SERVICE CAP_SETPCAP -AmbientCapabilities=CAP_NET_BIND_SERVICE CAP_SETPCAP -ExecStartPre=/usr/sbin/knotc conf-check -ExecStart=/usr/sbin/knotd -m "$KNOT_CONF_MAX_SIZE" -ExecReload=/bin/kill -HUP $MAINPID -Restart=on-abort -LimitNOFILE=1048576 -TimeoutStopSec=300 -# Extend the systemd startup timeout by this value (seconds) for each zone -Environment="KNOT_ZONE_LOAD_TIMEOUT_SEC=180" -# Maximum size (MiB) of a configuration database -Environment="KNOT_CONF_MAX_SIZE=512" - -[Install] -WantedBy=multi-user.target diff --git a/distro/pkg/el-7/knot.spec b/distro/pkg/el-7/knot.spec deleted file mode 100644 index 887f988..0000000 --- a/distro/pkg/el-7/knot.spec +++ /dev/null @@ -1,334 +0,0 @@ -%global _hardened_build 1 -%{!?_pkgdocdir: %global _pkgdocdir %{_docdir}/%{name}} - -%define GPG_CHECK 0 -%define BASE_VERSION %(echo "%{version}" | sed 's/^\\([^.]\\+\\.[^.]\\+\\).*/\\1/') -%define repodir %{_builddir}/%{name}-%{version} - -Summary: High-performance authoritative DNS server -Name: knot -Version: {{ version }} -Release: cznic.{{ release }}%{?dist} -License: GPL-3.0-or-later -URL: https://www.knot-dns.cz -Source0: %{name}-%{version}.tar.xz - -%if 0%{?GPG_CHECK} -Source1: https://secure.nic.cz/files/knot-dns/%{name}-%{version}.tar.xz.asc -# PGP keys used to sign upstream releases -# Export with --armor using command from https://fedoraproject.org/wiki/PackagingDrafts:GPGSignatures -# Don't forget to update %%prep section when adding/removing keys -Source100: gpgkey-742FA4E95829B6C5EAC6B85710BB7AF6FEBBD6AB.gpg.asc -BuildRequires: gnupg2 -%endif - -Patch1: 01-revert-AC_PROG_CC.patch -Patch2: 02-fix-compilation-by-using-SHA-1.patch -Patch3: 03-doc-don-t-try-to-import-sphinx_panels.patch -Patch4: 04-revert-don-t-share-PKCS-11-private-keys.patch -Patch5: 05-revert-mod-dnstap-TCP-sink.patch - -# Required dependencies -BuildRequires: autoconf -BuildRequires: automake -BuildRequires: libtool -BuildRequires: devtoolset-11-make -BuildRequires: devtoolset-11-gcc -BuildRequires: pkgconfig(liburcu) -BuildRequires: pkgconfig(gnutls) >= 3.3 -BuildRequires: pkgconfig(libedit) - -# Optional dependencies -BuildRequires: pkgconfig(libcap-ng) -BuildRequires: pkgconfig(libidn2) -BuildRequires: pkgconfig(libmnl) -BuildRequires: pkgconfig(libnghttp2) -BuildRequires: pkgconfig(libsystemd) -BuildRequires: pkgconfig(systemd) -# dnstap dependencies -BuildRequires: pkgconfig(libfstrm) -BuildRequires: pkgconfig(libprotobuf-c) -# geoip dependencies -BuildRequires: pkgconfig(libmaxminddb) - -# Distro-dependent dependencies -%if 0%{?suse_version} -BuildRequires: python3-Sphinx -BuildRequires: lmdb-devel -BuildRequires: protobuf-c -Requires(pre): pwdutils -%endif -%if 0%{?rhel} && 0%{?rhel} <= 7 -BuildRequires: python-sphinx -BuildRequires: lmdb-devel -%endif -%if 0%{?fedora} || 0%{?rhel} > 7 -BuildRequires: python3-sphinx -BuildRequires: pkgconfig(lmdb) -%endif - -# disable XDP on old EL -%define configure_xdp --enable-xdp=no - -Requires(post): systemd %{_sbindir}/runuser -Requires(preun): systemd -Requires(postun): systemd - -Conflicts: knot-resolver < 5.7.0 - -Requires: %{name}-libs%{?_isa} = %{version}-%{release} - -%description -Knot DNS is a high-performance authoritative DNS server implementation. - -%package libs -Summary: Libraries used by the Knot DNS server and client applications - -%description libs -The package contains shared libraries used by the Knot DNS server and -utilities. - -%package devel -Summary: Development header files for the Knot DNS libraries -Requires: %{name}-libs%{?_isa} = %{version}-%{release} - -%description devel -The package contains development header files for the Knot DNS libraries -included in knot-libs package. - -%package utils -Summary: DNS client utilities shipped with the Knot DNS server -Requires: %{name}-libs%{?_isa} = %{version}-%{release} -# Debian package compat -Provides: %{name}-dnsutils = %{version}-%{release} - -%description utils -The package contains DNS client utilities shipped with the Knot DNS server. - -%package dnssecutils -Summary: DNSSEC tools shipped with the Knot DNS server -Requires: %{name}-libs%{?_isa} = %{version}-%{release} - -%description dnssecutils -The package contains DNSSEC tools shipped with the Knot DNS server. - -%package module-dnstap -Summary: dnstap module for Knot DNS -Requires: %{name} = %{version}-%{release} - -%description module-dnstap -The package contains dnstap Knot DNS module for logging DNS traffic. - -%package module-geoip -Summary: geoip module for Knot DNS -Requires: %{name} = %{version}-%{release} - -%description module-geoip -The package contains geoip Knot DNS module for geography-based responses. - -%package doc -Summary: Documentation for the Knot DNS server -BuildArch: noarch -Provides: bundled(jquery) - -%description doc -The package contains documentation for the Knot DNS server. -On-line version is available on https://www.knot-dns.cz/documentation/ - -%prep -%if 0%{?GPG_CHECK} -export GNUPGHOME=./gpg-keyring -[ -d ${GNUPGHOME} ] && rm -r ${GNUPGHOME} -mkdir --mode=700 ${GNUPGHOME} -gpg2 --import %{SOURCE100} -gpg2 --verify %{SOURCE1} %{SOURCE0} -%endif -%autosetup -p1 - -%build -# disable debug code (causes unused warnings) -CFLAGS="%{optflags} -DNDEBUG -Wno-unused" - -%ifarch armv7hl i686 -# 32-bit architectures sometimes do not have sufficient amount of -# contiguous address space to handle default values -%define configure_db_sizes --with-conf-mapsize=64 -%endif - -autoreconf -if - -export CC="/opt/rh/devtoolset-11/root/usr/bin/gcc" -%configure \ - --sysconfdir=/etc \ - --localstatedir=/var/lib \ - --libexecdir=/usr/lib/knot \ - --with-rundir=/run/knot \ - --with-moduledir=%{_libdir}/knot/modules-%{BASE_VERSION} \ - --with-storage=/var/lib/knot \ - %{?configure_db_sizes} \ - %{?configure_xdp} \ - --disable-static \ - --enable-dnstap=yes \ - --with-module-dnstap=shared \ - --with-module-geoip=shared -make %{?_smp_mflags} -make html - -%install -make install DESTDIR=%{buildroot} - -# install documentation -install -d -m 0755 %{buildroot}%{_pkgdocdir}/samples -install -p -m 0644 -t %{buildroot}%{_pkgdocdir}/samples samples/*.zone* -install -p -m 0644 NEWS README.md %{buildroot}%{_pkgdocdir} -cp -av doc/_build/html %{buildroot}%{_pkgdocdir} -[ -r %{buildroot}%{_pkgdocdir}/html/index.html ] || exit 1 -rm -f %{buildroot}%{_pkgdocdir}/html/.buildinfo - -# install daemon and dbus configuration files -rm %{buildroot}%{_sysconfdir}/%{name}/* -install -p -m 0644 -D %{repodir}/samples/%{name}.sample.conf %{buildroot}%{_sysconfdir}/%{name}/%{name}.conf -%if 0%{?fedora} || 0%{?rhel} > 7 -install -p -m 0644 -D %{repodir}/distro/common/cz.nic.knotd.conf %{buildroot}%{_sysconfdir}/dbus-1/system.d/cz.nic.knotd.conf -%endif - -# install systemd files -install -p -m 0644 -D %{repodir}/distro/pkg/el-7/%{name}.service %{buildroot}%{_unitdir}/%{name}.service -install -p -m 0644 -D %{repodir}/distro/pkg/el-7/%{name}.tmpfiles %{buildroot}%{_tmpfilesdir}/%{name}.conf -%if 0%{?suse_version} -ln -s service %{buildroot}/%{_sbindir}/rcknot -%endif - -# create storage dir -install -d %{buildroot}%{_sharedstatedir} -install -d -m 0770 -D %{buildroot}%{_sharedstatedir}/knot - -# remove libarchive files -find %{buildroot} -type f -name "*.la" -delete -print - -%check -V=1 make check - -%pre -getent group knot >/dev/null || groupadd -r knot -getent passwd knot >/dev/null || \ - useradd -r -g knot -d %{_sharedstatedir}/knot -s /sbin/nologin \ - -c "Knot DNS server" knot -%if 0%{?suse_version} -%service_add_pre knot.service -%endif - -%post -systemd-tmpfiles --create %{_tmpfilesdir}/knot.conf &>/dev/null || : -%if 0%{?suse_version} -%service_add_post knot.service -%else -%systemd_post knot.service -%endif - -%preun -%if 0%{?suse_version} -%service_del_preun knot.service -%else -%systemd_preun knot.service -%endif - -%postun -%if 0%{?suse_version} -%service_del_postun knot.service -%else -%systemd_postun_with_restart knot.service -%endif - -%if 0%{?fedora} || 0%{?rhel} > 7 -# https://fedoraproject.org/wiki/Changes/Removing_ldconfig_scriptlets -%else -%post libs -p /sbin/ldconfig -%postun libs -p /sbin/ldconfig -%endif - -%files -%license COPYING -%doc %{_pkgdocdir} -%exclude %{_pkgdocdir}/html -%attr(770,root,knot) %dir %{_sysconfdir}/knot -%config(noreplace) %attr(640,root,knot) %{_sysconfdir}/knot/knot.conf -%if 0%{?fedora} || 0%{?rhel} > 7 -%config(noreplace) %attr(644,root,root) %{_sysconfdir}/dbus-1/system.d/cz.nic.knotd.conf -%endif -%attr(770,root,knot) %dir %{_sharedstatedir}/knot -%dir %{_libdir}/knot -%dir %{_libdir}/knot/modules-* -%{_unitdir}/knot.service -%{_tmpfilesdir}/knot.conf -%{_sbindir}/kcatalogprint -%{_sbindir}/kjournalprint -%{_sbindir}/keymgr -%{_sbindir}/knotc -%{_sbindir}/knotd -%if 0%{?suse_version} -%{_sbindir}/rcknot -%endif -%{_mandir}/man5/knot.conf.* -%{_mandir}/man8/kcatalogprint.* -%{_mandir}/man8/kjournalprint.* -%{_mandir}/man8/keymgr.* -%{_mandir}/man8/knotc.* -%{_mandir}/man8/knotd.* -%ghost %attr(770,root,knot) %dir %{_rundir}/knot - -%files utils -%{_bindir}/kdig -%{_bindir}/khost -%{_bindir}/knsupdate -%if 0%{?use_xdp} -%{_sbindir}/kxdpgun -%{_mandir}/man8/kxdpgun.* -%endif -%{_mandir}/man1/kdig.* -%{_mandir}/man1/khost.* -%{_mandir}/man1/knsupdate.* - -%files dnssecutils -%{_bindir}/knsec3hash -%{_bindir}/kzonecheck -%{_bindir}/kzonesign -%{_mandir}/man1/knsec3hash.* -%{_mandir}/man1/kzonecheck.* -%{_mandir}/man1/kzonesign.* - -%files module-dnstap -%{_libdir}/knot/modules-*/dnstap.so - -%files module-geoip -%{_libdir}/knot/modules-*/geoip.so - -%files libs -%license COPYING -%doc NEWS -%doc README.md -%{_libdir}/libdnssec.so.* -%{_libdir}/libknot.so.* -%{_libdir}/libzscanner.so.* - -%files devel -%{_includedir}/libdnssec -%{_includedir}/knot -%{_includedir}/libknot -%{_includedir}/libzscanner -%{_libdir}/libdnssec.so -%{_libdir}/libknot.so -%{_libdir}/libzscanner.so -%{_libdir}/pkgconfig/knotd.pc -%{_libdir}/pkgconfig/libdnssec.pc -%{_libdir}/pkgconfig/libknot.pc -%{_libdir}/pkgconfig/libzscanner.pc - -%files doc -%dir %{_pkgdocdir} -%doc %{_pkgdocdir}/html - -%changelog -* {{ now }} Jakub Ružička <jakub.ruzicka@nic.cz> - {{ version }}-{{ release }} -- upstream package -- see https://www.knot-dns.cz diff --git a/distro/pkg/el-7/knot.tmpfiles b/distro/pkg/el-7/knot.tmpfiles deleted file mode 100644 index edec729..0000000 --- a/distro/pkg/el-7/knot.tmpfiles +++ /dev/null @@ -1,3 +0,0 @@ -# tmpfiles.d(5) runtime directory for knot -#Type Path Mode UID GID Age Argument - d /run/knot 0755 knot knot - - diff --git a/distro/pkg/rpm/knot.spec b/distro/pkg/rpm/knot.spec index 3a7d89e..c99ea55 100644 --- a/distro/pkg/rpm/knot.spec +++ b/distro/pkg/rpm/knot.spec @@ -84,7 +84,7 @@ Knot DNS is a high-performance authoritative DNS server implementation. %package libs Summary: Libraries used by the Knot DNS server and client applications -Conflicts: knot-resolver < 5.7.0 +Conflicts: knot-resolver < 5.7.3 %description libs The package contains shared libraries used by the Knot DNS server and diff --git a/doc/Makefile.am b/doc/Makefile.am index b26e298..71d561c 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -1,18 +1,3 @@ -MANPAGES_IN = \ - man/knot.conf.5in \ - man/knotc.8in \ - man/knotd.8in \ - man/kcatalogprint.8in \ - man/keymgr.8in \ - man/kjournalprint.8in \ - man/kdig.1in \ - man/khost.1in \ - man/knsupdate.1in \ - man/knsec3hash.1in \ - man/kzonecheck.1in \ - man/kzonesign.1in \ - man/kxdpgun.8in - MANPAGES_RST = \ reference.rst \ man_knotc.rst \ @@ -44,7 +29,6 @@ EXTRA_DIST = \ troubleshooting.rst \ utilities.rst \ \ - $(MANPAGES_IN) \ $(MANPAGES_RST) \ \ logo.pdf \ @@ -66,27 +50,26 @@ SPHINXBUILDDIR = $(builddir)/_build _SPHINXOPTS = -c $(srcdir) \ -a \ - $(SPHINX_V) - -ALLSPHINXOPTS = $(_SPHINXOPTS) \ + $(SPHINX_V) \ -D version="$(VERSION)" \ -D today="$(RELEASE_DATE)" \ - -D release="$(VERSION)" \ + -D release="$(VERSION)" + +ALLSPHINXOPTS = $(_SPHINXOPTS) \ $(SPHINXOPTS) \ $(srcdir) man_SPHINXOPTS = $(_SPHINXOPTS) \ - -D version="@""VERSION@" \ - -D today="@""RELEASE_DATE@" \ - -D release="@""VERSION@" \ -D extensions="ignore_panels" \ $(SPHINXOPTS) \ $(srcdir) -.PHONY: html-local singlehtml pdf-local info-local epub man install-html-local install-singlehtml install-pdf-local install-info-local install-epub +.PHONY: html-local singlehtml pdf-local epub man install-html-local install-singlehtml install-pdf-local install-epub man_MANS = +if HAVE_DOCS + if HAVE_DAEMON man_MANS += \ man/knot.conf.5 \ @@ -115,43 +98,8 @@ man_MANS += man/kxdpgun.8 endif # ENABLE_XDP endif # HAVE_UTILS -man/knot.conf.5: man/knot.conf.5in -man/knotc.8: man/knotc.8in -man/knotd.8: man/knotd.8in -man/kcatalogprint.8: man/kcatalogprint.8in -man/keymgr.8: man/keymgr.8in -man/kjournalprint.8: man/kjournalprint.8in -man/kdig.1: man/kdig.1in -man/khost.1: man/khost.1in -man/knsupdate.1: man/knsupdate.1in -man/knsec3hash.1: man/knsec3hash.1in -man/kzonecheck.1: man/kzonecheck.1in -man/kzonesign.1: man/kzonesign.1in -man/kxdpgun.8: man/kxdpgun.8in - -man_SUBST = $(AM_V_GEN)mkdir -p man; \ - sed -e 's,[@]VERSION@,$(VERSION),' \ - -e 's,[@]RELEASE_DATE@,$(RELEASE_DATE),' \ - -e 's,[@]config_dir@,$(config_dir),' \ - -e 's,[@]storage_dir@,$(storage_dir),' \ - -e 's,[@]run_dir@,$(run_dir),' \ - -e 's,[@]conf_mapsize@,$(conf_mapsize),' \ - $< > $@ - -.1in.1: - $(man_SUBST) - -.5in.5: - $(man_SUBST) - -.8in.8: - $(man_SUBST) - -if HAVE_DOCS - -if HAVE_SPHINXBUILD html-local: - $(AM_V_SPHINX)$(SPHINXBUILD) -b html -d $(SPHINXBUILDDIR)/doctrees $(ALLSPHINXOPTS) $(SPHINXBUILDDIR)/html + $(AM_V_SPHINX)$(SPHINXBUILD) -b html -d $(SPHINXBUILDDIR)/doctrees/html $(ALLSPHINXOPTS) $(SPHINXBUILDDIR)/html @echo "The HTML documentation has been built in $(SPHINXBUILDDIR)/html/" install-html-local: @@ -161,7 +109,7 @@ install-html-local: $(INSTALL_DATA) $(SPHINXBUILDDIR)/html/_static/* $(DESTDIR)/$(docdir)/_static/ singlehtml: - $(AM_V_SPHINX)$(SPHINXBUILD) -b singlehtml -d $(SPHINXBUILDDIR)/doctrees $(ALLSPHINXOPTS) $(SPHINXBUILDDIR)/singlehtml + $(AM_V_SPHINX)$(SPHINXBUILD) -b singlehtml -d $(SPHINXBUILDDIR)/doctrees/singlehtml $(ALLSPHINXOPTS) $(SPHINXBUILDDIR)/singlehtml @echo "The single HTML documentation has been built in $(SPHINXBUILDDIR)/singlehtml/" install-singlehtml: singlehtml @@ -170,7 +118,7 @@ install-singlehtml: singlehtml $(INSTALL_DATA) $(SPHINXBUILDDIR)/singlehtml/_static/* $(DESTDIR)/$(docdir)/_static/ epub: - $(AM_V_SPHINX)$(SPHINXBUILD) -b epub -A today=$(RELEASE_DATE) -d $(SPHINXBUILDDIR)/doctrees $(ALLSPHINXOPTS) $(SPHINXBUILDDIR)/epub + $(AM_V_SPHINX)$(SPHINXBUILD) -b epub -A today=$(RELEASE_DATE) -d $(SPHINXBUILDDIR)/doctrees/epub $(ALLSPHINXOPTS) $(SPHINXBUILDDIR)/epub @echo "The EPUB documentation has been built in $(SPHINXBUILDDIR)/epub/" install-epub: @@ -179,7 +127,7 @@ install-epub: if HAVE_PDFLATEX pdf-local: - $(AM_V_SPHINX)$(SPHINXBUILD) -b latex -d $(SPHINXBUILDDIR)/doctrees $(ALLSPHINXOPTS) $(SPHINXBUILDDIR)/latex + $(AM_V_SPHINX)$(SPHINXBUILD) -b latex -d $(SPHINXBUILDDIR)/doctrees/latex $(ALLSPHINXOPTS) $(SPHINXBUILDDIR)/latex $(MAKE) -C $(SPHINXBUILDDIR)/latex all-pdf @echo "The PDF documentation has been built in $(SPHINXBUILDDIR)/latex/" @@ -192,37 +140,26 @@ pdf-local install-pdf-local: @echo "Install 'pdflatex' and re-run configure to be able to generate PDF documentation!" endif # HAVE_PDFLATEX -if HAVE_MAKEINFO -info-local: - $(AM_V_SPHINX)$(SPHINXBUILD) -b texinfo -d $(SPHINXBUILDDIR)/doctrees $(ALLSPHINXOPTS) $(SPHINXBUILDDIR)/texinfo - $(MAKE) -C $(SPHINXBUILDDIR)/texinfo info - @echo "The Info pages have been built in $(SPHINXBUILDDIR)/texinfo/" - -install-info-local: - $(INSTALL) -d $(DESTDIR)/$(infodir) - $(INSTALL_DATA) $(SPHINXBUILDDIR)/texinfo/knot.info $(DESTDIR)/$(infodir)/ - -else -info-local install-info-local: - @echo "Install 'texinfo' and re-run configure to be able to generate Info pages!" -endif # HAVE_MAKEINFO - -.NOTPARALLEL: man man: $(man_MANS) -$(MANPAGES_IN): $(MANPAGES_RST) - $(AM_V_SPHINX)$(SPHINXBUILD) -b man -d $(SPHINXBUILDDIR)/doctrees $(man_SPHINXOPTS) $(SPHINXBUILDDIR)/man - @mkdir -p $(srcdir)/man +$(man_MANS)&: $(MANPAGES_RST) + $(AM_V_SPHINX)$(SPHINXBUILD) -b man -d $(SPHINXBUILDDIR)/doctrees/man $(man_SPHINXOPTS) $(SPHINXBUILDDIR)/man + @mkdir -p man @for f in $(SPHINXBUILDDIR)/man/*; do \ - sed -e '/^\.TP$$/ {' -e 'n' -e 's/^\.B //' -e '}' "$$f" > "$(srcdir)/man/$$(basename $$f)in"; \ + sed -e 's,[@]config_dir@,$(config_dir),' \ + -e 's,[@]storage_dir@,$(storage_dir),' \ + -e 's,[@]run_dir@,$(run_dir),' \ + -e 's,[@]conf_mapsize@,$(conf_mapsize),' "$$f" > "man/$$(basename $$f)"; \ done else -html-local singlehtml pdf-local info-local epub man install-html-local install-singlehtml install-pdf-local install-info-local install-epub: +html-local singlehtml pdf-local epub man install-html-local install-singlehtml install-pdf-local install-epub: @echo "Install 'sphinx-build' and re-run configure to be able to generate documentation!" -endif # HAVE_SPHINXBUILD endif # HAVE_DOCS +EXTRA_DIST += \ + $(man_MANS) + clean-local: -rm -rf $(SPHINXBUILDDIR) - -rm -f man/*.1 man/*.5 man/*.8 + -rm -rf man diff --git a/doc/Makefile.in b/doc/Makefile.in index 5642629..a7bacd9 100644 --- a/doc/Makefile.in +++ b/doc/Makefile.in @@ -87,25 +87,25 @@ PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ -@HAVE_DAEMON_TRUE@am__append_1 = \ -@HAVE_DAEMON_TRUE@ man/knot.conf.5 \ -@HAVE_DAEMON_TRUE@ man/knotc.8 \ -@HAVE_DAEMON_TRUE@ man/knotd.8 - -@HAVE_DAEMON_TRUE@@HAVE_UTILS_TRUE@am__append_2 = \ -@HAVE_DAEMON_TRUE@@HAVE_UTILS_TRUE@ man/kcatalogprint.8 \ -@HAVE_DAEMON_TRUE@@HAVE_UTILS_TRUE@ man/keymgr.8 \ -@HAVE_DAEMON_TRUE@@HAVE_UTILS_TRUE@ man/kjournalprint.8 \ -@HAVE_DAEMON_TRUE@@HAVE_UTILS_TRUE@ man/kzonecheck.1 \ -@HAVE_DAEMON_TRUE@@HAVE_UTILS_TRUE@ man/kzonesign.1 - -@HAVE_UTILS_TRUE@am__append_3 = \ -@HAVE_UTILS_TRUE@ man/kdig.1 \ -@HAVE_UTILS_TRUE@ man/khost.1 \ -@HAVE_UTILS_TRUE@ man/knsupdate.1 \ -@HAVE_UTILS_TRUE@ man/knsec3hash.1 - -@ENABLE_XDP_TRUE@@HAVE_UTILS_TRUE@am__append_4 = man/kxdpgun.8 +@HAVE_DAEMON_TRUE@@HAVE_DOCS_TRUE@am__append_1 = \ +@HAVE_DAEMON_TRUE@@HAVE_DOCS_TRUE@ man/knot.conf.5 \ +@HAVE_DAEMON_TRUE@@HAVE_DOCS_TRUE@ man/knotc.8 \ +@HAVE_DAEMON_TRUE@@HAVE_DOCS_TRUE@ man/knotd.8 + +@HAVE_DAEMON_TRUE@@HAVE_DOCS_TRUE@@HAVE_UTILS_TRUE@am__append_2 = \ +@HAVE_DAEMON_TRUE@@HAVE_DOCS_TRUE@@HAVE_UTILS_TRUE@ man/kcatalogprint.8 \ +@HAVE_DAEMON_TRUE@@HAVE_DOCS_TRUE@@HAVE_UTILS_TRUE@ man/keymgr.8 \ +@HAVE_DAEMON_TRUE@@HAVE_DOCS_TRUE@@HAVE_UTILS_TRUE@ man/kjournalprint.8 \ +@HAVE_DAEMON_TRUE@@HAVE_DOCS_TRUE@@HAVE_UTILS_TRUE@ man/kzonecheck.1 \ +@HAVE_DAEMON_TRUE@@HAVE_DOCS_TRUE@@HAVE_UTILS_TRUE@ man/kzonesign.1 + +@HAVE_DOCS_TRUE@@HAVE_UTILS_TRUE@am__append_3 = \ +@HAVE_DOCS_TRUE@@HAVE_UTILS_TRUE@ man/kdig.1 \ +@HAVE_DOCS_TRUE@@HAVE_UTILS_TRUE@ man/khost.1 \ +@HAVE_DOCS_TRUE@@HAVE_UTILS_TRUE@ man/knsupdate.1 \ +@HAVE_DOCS_TRUE@@HAVE_UTILS_TRUE@ man/knsec3hash.1 + +@ENABLE_XDP_TRUE@@HAVE_DOCS_TRUE@@HAVE_UTILS_TRUE@am__append_4 = man/kxdpgun.8 subdir = doc ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_compile_flag.m4 \ @@ -312,6 +312,8 @@ infodir = @infodir@ install_sh = @install_sh@ libbpf_CFLAGS = @libbpf_CFLAGS@ libbpf_LIBS = @libbpf_LIBS@ +libdbus_CFLAGS = @libdbus_CFLAGS@ +libdbus_LIBS = @libdbus_LIBS@ libdir = @libdir@ libdnssec_SONAME = @libdnssec_SONAME@ libdnssec_SOVERSION = @libdnssec_SOVERSION@ @@ -323,8 +325,6 @@ libfstrm_CFLAGS = @libfstrm_CFLAGS@ libfstrm_LIBS = @libfstrm_LIBS@ libidn2_CFLAGS = @libidn2_CFLAGS@ libidn2_LIBS = @libidn2_LIBS@ -libidn_CFLAGS = @libidn_CFLAGS@ -libidn_LIBS = @libidn_LIBS@ libknot_SONAME = @libknot_SONAME@ libknot_SOVERSION = @libknot_SOVERSION@ libknot_VERSION_INFO = @libknot_VERSION_INFO@ @@ -342,7 +342,6 @@ libprotobuf_c_CFLAGS = @libprotobuf_c_CFLAGS@ libprotobuf_c_LIBS = @libprotobuf_c_LIBS@ liburcu_CFLAGS = @liburcu_CFLAGS@ liburcu_LIBS = @liburcu_LIBS@ -liburcu_PKGCONFIG = @liburcu_PKGCONFIG@ libxdp_CFLAGS = @libxdp_CFLAGS@ libxdp_LIBS = @libxdp_LIBS@ libzscanner_SONAME = @libzscanner_SONAME@ @@ -378,21 +377,6 @@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ -MANPAGES_IN = \ - man/knot.conf.5in \ - man/knotc.8in \ - man/knotd.8in \ - man/kcatalogprint.8in \ - man/keymgr.8in \ - man/kjournalprint.8in \ - man/kdig.1in \ - man/khost.1in \ - man/knsupdate.1in \ - man/knsec3hash.1in \ - man/kzonecheck.1in \ - man/kzonesign.1in \ - man/kxdpgun.8in - MANPAGES_RST = \ reference.rst \ man_knotc.rst \ @@ -408,31 +392,11 @@ MANPAGES_RST = \ man_kzonesign.rst \ man_kxdpgun.rst -EXTRA_DIST = \ - conf.py \ - \ - appendices.rst \ - configuration.rst \ - index.rst \ - installation.rst \ - introduction.rst \ - migration.rst \ - modules.rst.in \ - operation.rst \ - reference.rst \ - requirements.rst \ - troubleshooting.rst \ - utilities.rst \ - \ - $(MANPAGES_IN) \ - $(MANPAGES_RST) \ - \ - logo.pdf \ - logo.svg \ - \ - ext/ignore_panels.py \ - theme_html - +EXTRA_DIST = conf.py appendices.rst configuration.rst index.rst \ + installation.rst introduction.rst migration.rst modules.rst.in \ + operation.rst reference.rst requirements.rst \ + troubleshooting.rst utilities.rst $(MANPAGES_RST) logo.pdf \ + logo.svg ext/ignore_panels.py theme_html $(man_MANS) SPHINX_V = $(SPHINX_V_@AM_V@) SPHINX_V_ = $(SPHINX_V_@AM_DEFAULT_V@) SPHINX_V_0 = -q @@ -443,38 +407,25 @@ AM_V_SPHINX_0 = @echo " SPHINX $@"; SPHINXBUILDDIR = $(builddir)/_build _SPHINXOPTS = -c $(srcdir) \ -a \ - $(SPHINX_V) - -ALLSPHINXOPTS = $(_SPHINXOPTS) \ + $(SPHINX_V) \ -D version="$(VERSION)" \ -D today="$(RELEASE_DATE)" \ - -D release="$(VERSION)" \ + -D release="$(VERSION)" + +ALLSPHINXOPTS = $(_SPHINXOPTS) \ $(SPHINXOPTS) \ $(srcdir) man_SPHINXOPTS = $(_SPHINXOPTS) \ - -D version="@""VERSION@" \ - -D today="@""RELEASE_DATE@" \ - -D release="@""VERSION@" \ -D extensions="ignore_panels" \ $(SPHINXOPTS) \ $(srcdir) man_MANS = $(am__append_1) $(am__append_2) $(am__append_3) \ $(am__append_4) -man_SUBST = $(AM_V_GEN)mkdir -p man; \ - sed -e 's,[@]VERSION@,$(VERSION),' \ - -e 's,[@]RELEASE_DATE@,$(RELEASE_DATE),' \ - -e 's,[@]config_dir@,$(config_dir),' \ - -e 's,[@]storage_dir@,$(storage_dir),' \ - -e 's,[@]run_dir@,$(run_dir),' \ - -e 's,[@]conf_mapsize@,$(conf_mapsize),' \ - $< > $@ - all: all-am .SUFFIXES: -.SUFFIXES: .1 .1in .5 .5in .8 .8in $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ @@ -718,21 +669,11 @@ maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." @HAVE_DOCS_FALSE@html-local: -@HAVE_SPHINXBUILD_FALSE@html-local: -@HAVE_DOCS_FALSE@info-local: -@HAVE_MAKEINFO_FALSE@info-local: -@HAVE_SPHINXBUILD_FALSE@info-local: @HAVE_DOCS_FALSE@install-html-local: -@HAVE_SPHINXBUILD_FALSE@install-html-local: -@HAVE_DOCS_FALSE@install-info-local: -@HAVE_MAKEINFO_FALSE@install-info-local: -@HAVE_SPHINXBUILD_FALSE@install-info-local: @HAVE_DOCS_FALSE@install-pdf-local: @HAVE_PDFLATEX_FALSE@install-pdf-local: -@HAVE_SPHINXBUILD_FALSE@install-pdf-local: @HAVE_DOCS_FALSE@pdf-local: @HAVE_PDFLATEX_FALSE@pdf-local: -@HAVE_SPHINXBUILD_FALSE@pdf-local: clean: clean-am clean-am: clean-generic clean-libtool clean-local mostlyclean-am @@ -751,7 +692,7 @@ html-am: html-local info: info-am -info-am: info-local +info-am: install-data-am: install-man @@ -767,7 +708,7 @@ install-html-am: install-html-local install-info: install-info-am -install-info-am: install-info-local +install-info-am: install-man: install-man1 install-man5 install-man8 @@ -806,11 +747,10 @@ uninstall-man: uninstall-man1 uninstall-man5 uninstall-man8 .PHONY: all all-am check check-am clean clean-generic clean-libtool \ clean-local cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am html-local \ - info info-am info-local install install-am install-data \ - install-data-am install-dvi install-dvi-am install-exec \ - install-exec-am install-html install-html-am \ - install-html-local install-info install-info-am \ - install-info-local install-man install-man1 install-man5 \ + 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-html-local install-info \ + install-info-am install-man install-man1 install-man5 \ install-man8 install-pdf install-pdf-am install-pdf-local \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ @@ -822,97 +762,64 @@ uninstall-man: uninstall-man1 uninstall-man5 uninstall-man8 .PRECIOUS: Makefile -.PHONY: html-local singlehtml pdf-local info-local epub man install-html-local install-singlehtml install-pdf-local install-info-local install-epub - -man/knot.conf.5: man/knot.conf.5in -man/knotc.8: man/knotc.8in -man/knotd.8: man/knotd.8in -man/kcatalogprint.8: man/kcatalogprint.8in -man/keymgr.8: man/keymgr.8in -man/kjournalprint.8: man/kjournalprint.8in -man/kdig.1: man/kdig.1in -man/khost.1: man/khost.1in -man/knsupdate.1: man/knsupdate.1in -man/knsec3hash.1: man/knsec3hash.1in -man/kzonecheck.1: man/kzonecheck.1in -man/kzonesign.1: man/kzonesign.1in -man/kxdpgun.8: man/kxdpgun.8in - -.1in.1: - $(man_SUBST) - -.5in.5: - $(man_SUBST) - -.8in.8: - $(man_SUBST) - -@HAVE_DOCS_TRUE@@HAVE_SPHINXBUILD_TRUE@html-local: -@HAVE_DOCS_TRUE@@HAVE_SPHINXBUILD_TRUE@ $(AM_V_SPHINX)$(SPHINXBUILD) -b html -d $(SPHINXBUILDDIR)/doctrees $(ALLSPHINXOPTS) $(SPHINXBUILDDIR)/html -@HAVE_DOCS_TRUE@@HAVE_SPHINXBUILD_TRUE@ @echo "The HTML documentation has been built in $(SPHINXBUILDDIR)/html/" - -@HAVE_DOCS_TRUE@@HAVE_SPHINXBUILD_TRUE@install-html-local: -@HAVE_DOCS_TRUE@@HAVE_SPHINXBUILD_TRUE@ $(INSTALL) -d $(DESTDIR)/$(docdir) $(DESTDIR)/$(docdir)/_static $(DESTDIR)/$(docdir)/_sources -@HAVE_DOCS_TRUE@@HAVE_SPHINXBUILD_TRUE@ $(INSTALL) -D $(SPHINXBUILDDIR)/html/*.html $(DESTDIR)/$(docdir)/ -@HAVE_DOCS_TRUE@@HAVE_SPHINXBUILD_TRUE@ $(INSTALL_DATA) $(SPHINXBUILDDIR)/html/_sources/* $(DESTDIR)/$(docdir)/_sources/ -@HAVE_DOCS_TRUE@@HAVE_SPHINXBUILD_TRUE@ $(INSTALL_DATA) $(SPHINXBUILDDIR)/html/_static/* $(DESTDIR)/$(docdir)/_static/ - -@HAVE_DOCS_TRUE@@HAVE_SPHINXBUILD_TRUE@singlehtml: -@HAVE_DOCS_TRUE@@HAVE_SPHINXBUILD_TRUE@ $(AM_V_SPHINX)$(SPHINXBUILD) -b singlehtml -d $(SPHINXBUILDDIR)/doctrees $(ALLSPHINXOPTS) $(SPHINXBUILDDIR)/singlehtml -@HAVE_DOCS_TRUE@@HAVE_SPHINXBUILD_TRUE@ @echo "The single HTML documentation has been built in $(SPHINXBUILDDIR)/singlehtml/" - -@HAVE_DOCS_TRUE@@HAVE_SPHINXBUILD_TRUE@install-singlehtml: singlehtml -@HAVE_DOCS_TRUE@@HAVE_SPHINXBUILD_TRUE@ $(INSTALL) -d $(DESTDIR)/$(docdir) $(DESTDIR)/$(docdir)/_static -@HAVE_DOCS_TRUE@@HAVE_SPHINXBUILD_TRUE@ $(INSTALL_DATA) $(SPHINXBUILDDIR)/singlehtml/*.html $(DESTDIR)/$(docdir)/ -@HAVE_DOCS_TRUE@@HAVE_SPHINXBUILD_TRUE@ $(INSTALL_DATA) $(SPHINXBUILDDIR)/singlehtml/_static/* $(DESTDIR)/$(docdir)/_static/ - -@HAVE_DOCS_TRUE@@HAVE_SPHINXBUILD_TRUE@epub: -@HAVE_DOCS_TRUE@@HAVE_SPHINXBUILD_TRUE@ $(AM_V_SPHINX)$(SPHINXBUILD) -b epub -A today=$(RELEASE_DATE) -d $(SPHINXBUILDDIR)/doctrees $(ALLSPHINXOPTS) $(SPHINXBUILDDIR)/epub -@HAVE_DOCS_TRUE@@HAVE_SPHINXBUILD_TRUE@ @echo "The EPUB documentation has been built in $(SPHINXBUILDDIR)/epub/" - -@HAVE_DOCS_TRUE@@HAVE_SPHINXBUILD_TRUE@install-epub: -@HAVE_DOCS_TRUE@@HAVE_SPHINXBUILD_TRUE@ $(INSTALL) -d $(DESTDIR)/$(docdir) -@HAVE_DOCS_TRUE@@HAVE_SPHINXBUILD_TRUE@ $(INSTALL_DATA) $(SPHINXBUILDDIR)/epub/KnotDNS.epub $(DESTDIR)/$(docdir)/ - -@HAVE_DOCS_TRUE@@HAVE_PDFLATEX_TRUE@@HAVE_SPHINXBUILD_TRUE@pdf-local: -@HAVE_DOCS_TRUE@@HAVE_PDFLATEX_TRUE@@HAVE_SPHINXBUILD_TRUE@ $(AM_V_SPHINX)$(SPHINXBUILD) -b latex -d $(SPHINXBUILDDIR)/doctrees $(ALLSPHINXOPTS) $(SPHINXBUILDDIR)/latex -@HAVE_DOCS_TRUE@@HAVE_PDFLATEX_TRUE@@HAVE_SPHINXBUILD_TRUE@ $(MAKE) -C $(SPHINXBUILDDIR)/latex all-pdf -@HAVE_DOCS_TRUE@@HAVE_PDFLATEX_TRUE@@HAVE_SPHINXBUILD_TRUE@ @echo "The PDF documentation has been built in $(SPHINXBUILDDIR)/latex/" - -@HAVE_DOCS_TRUE@@HAVE_PDFLATEX_TRUE@@HAVE_SPHINXBUILD_TRUE@install-pdf-local: -@HAVE_DOCS_TRUE@@HAVE_PDFLATEX_TRUE@@HAVE_SPHINXBUILD_TRUE@ $(INSTALL) -d $(DESTDIR)/$(docdir) -@HAVE_DOCS_TRUE@@HAVE_PDFLATEX_TRUE@@HAVE_SPHINXBUILD_TRUE@ $(INSTALL_DATA) $(SPHINXBUILDDIR)/latex/KnotDNS.pdf $(DESTDIR)/$(docdir)/ - -@HAVE_DOCS_TRUE@@HAVE_PDFLATEX_FALSE@@HAVE_SPHINXBUILD_TRUE@pdf-local install-pdf-local: -@HAVE_DOCS_TRUE@@HAVE_PDFLATEX_FALSE@@HAVE_SPHINXBUILD_TRUE@ @echo "Install 'pdflatex' and re-run configure to be able to generate PDF documentation!" - -@HAVE_DOCS_TRUE@@HAVE_MAKEINFO_TRUE@@HAVE_SPHINXBUILD_TRUE@info-local: -@HAVE_DOCS_TRUE@@HAVE_MAKEINFO_TRUE@@HAVE_SPHINXBUILD_TRUE@ $(AM_V_SPHINX)$(SPHINXBUILD) -b texinfo -d $(SPHINXBUILDDIR)/doctrees $(ALLSPHINXOPTS) $(SPHINXBUILDDIR)/texinfo -@HAVE_DOCS_TRUE@@HAVE_MAKEINFO_TRUE@@HAVE_SPHINXBUILD_TRUE@ $(MAKE) -C $(SPHINXBUILDDIR)/texinfo info -@HAVE_DOCS_TRUE@@HAVE_MAKEINFO_TRUE@@HAVE_SPHINXBUILD_TRUE@ @echo "The Info pages have been built in $(SPHINXBUILDDIR)/texinfo/" - -@HAVE_DOCS_TRUE@@HAVE_MAKEINFO_TRUE@@HAVE_SPHINXBUILD_TRUE@install-info-local: -@HAVE_DOCS_TRUE@@HAVE_MAKEINFO_TRUE@@HAVE_SPHINXBUILD_TRUE@ $(INSTALL) -d $(DESTDIR)/$(infodir) -@HAVE_DOCS_TRUE@@HAVE_MAKEINFO_TRUE@@HAVE_SPHINXBUILD_TRUE@ $(INSTALL_DATA) $(SPHINXBUILDDIR)/texinfo/knot.info $(DESTDIR)/$(infodir)/ - -@HAVE_DOCS_TRUE@@HAVE_MAKEINFO_FALSE@@HAVE_SPHINXBUILD_TRUE@info-local install-info-local: -@HAVE_DOCS_TRUE@@HAVE_MAKEINFO_FALSE@@HAVE_SPHINXBUILD_TRUE@ @echo "Install 'texinfo' and re-run configure to be able to generate Info pages!" - -@HAVE_DOCS_TRUE@@HAVE_SPHINXBUILD_TRUE@.NOTPARALLEL: man -@HAVE_DOCS_TRUE@@HAVE_SPHINXBUILD_TRUE@man: $(man_MANS) -@HAVE_DOCS_TRUE@@HAVE_SPHINXBUILD_TRUE@$(MANPAGES_IN): $(MANPAGES_RST) -@HAVE_DOCS_TRUE@@HAVE_SPHINXBUILD_TRUE@ $(AM_V_SPHINX)$(SPHINXBUILD) -b man -d $(SPHINXBUILDDIR)/doctrees $(man_SPHINXOPTS) $(SPHINXBUILDDIR)/man -@HAVE_DOCS_TRUE@@HAVE_SPHINXBUILD_TRUE@ @mkdir -p $(srcdir)/man -@HAVE_DOCS_TRUE@@HAVE_SPHINXBUILD_TRUE@ @for f in $(SPHINXBUILDDIR)/man/*; do \ -@HAVE_DOCS_TRUE@@HAVE_SPHINXBUILD_TRUE@ sed -e '/^\.TP$$/ {' -e 'n' -e 's/^\.B //' -e '}' "$$f" > "$(srcdir)/man/$$(basename $$f)in"; \ -@HAVE_DOCS_TRUE@@HAVE_SPHINXBUILD_TRUE@ done - -@HAVE_DOCS_TRUE@@HAVE_SPHINXBUILD_FALSE@html-local singlehtml pdf-local info-local epub man install-html-local install-singlehtml install-pdf-local install-info-local install-epub: -@HAVE_DOCS_TRUE@@HAVE_SPHINXBUILD_FALSE@ @echo "Install 'sphinx-build' and re-run configure to be able to generate documentation!" +.PHONY: html-local singlehtml pdf-local epub man install-html-local install-singlehtml install-pdf-local install-epub + +@HAVE_DOCS_TRUE@html-local: +@HAVE_DOCS_TRUE@ $(AM_V_SPHINX)$(SPHINXBUILD) -b html -d $(SPHINXBUILDDIR)/doctrees/html $(ALLSPHINXOPTS) $(SPHINXBUILDDIR)/html +@HAVE_DOCS_TRUE@ @echo "The HTML documentation has been built in $(SPHINXBUILDDIR)/html/" + +@HAVE_DOCS_TRUE@install-html-local: +@HAVE_DOCS_TRUE@ $(INSTALL) -d $(DESTDIR)/$(docdir) $(DESTDIR)/$(docdir)/_static $(DESTDIR)/$(docdir)/_sources +@HAVE_DOCS_TRUE@ $(INSTALL) -D $(SPHINXBUILDDIR)/html/*.html $(DESTDIR)/$(docdir)/ +@HAVE_DOCS_TRUE@ $(INSTALL_DATA) $(SPHINXBUILDDIR)/html/_sources/* $(DESTDIR)/$(docdir)/_sources/ +@HAVE_DOCS_TRUE@ $(INSTALL_DATA) $(SPHINXBUILDDIR)/html/_static/* $(DESTDIR)/$(docdir)/_static/ + +@HAVE_DOCS_TRUE@singlehtml: +@HAVE_DOCS_TRUE@ $(AM_V_SPHINX)$(SPHINXBUILD) -b singlehtml -d $(SPHINXBUILDDIR)/doctrees/singlehtml $(ALLSPHINXOPTS) $(SPHINXBUILDDIR)/singlehtml +@HAVE_DOCS_TRUE@ @echo "The single HTML documentation has been built in $(SPHINXBUILDDIR)/singlehtml/" + +@HAVE_DOCS_TRUE@install-singlehtml: singlehtml +@HAVE_DOCS_TRUE@ $(INSTALL) -d $(DESTDIR)/$(docdir) $(DESTDIR)/$(docdir)/_static +@HAVE_DOCS_TRUE@ $(INSTALL_DATA) $(SPHINXBUILDDIR)/singlehtml/*.html $(DESTDIR)/$(docdir)/ +@HAVE_DOCS_TRUE@ $(INSTALL_DATA) $(SPHINXBUILDDIR)/singlehtml/_static/* $(DESTDIR)/$(docdir)/_static/ + +@HAVE_DOCS_TRUE@epub: +@HAVE_DOCS_TRUE@ $(AM_V_SPHINX)$(SPHINXBUILD) -b epub -A today=$(RELEASE_DATE) -d $(SPHINXBUILDDIR)/doctrees/epub $(ALLSPHINXOPTS) $(SPHINXBUILDDIR)/epub +@HAVE_DOCS_TRUE@ @echo "The EPUB documentation has been built in $(SPHINXBUILDDIR)/epub/" + +@HAVE_DOCS_TRUE@install-epub: +@HAVE_DOCS_TRUE@ $(INSTALL) -d $(DESTDIR)/$(docdir) +@HAVE_DOCS_TRUE@ $(INSTALL_DATA) $(SPHINXBUILDDIR)/epub/KnotDNS.epub $(DESTDIR)/$(docdir)/ + +@HAVE_DOCS_TRUE@@HAVE_PDFLATEX_TRUE@pdf-local: +@HAVE_DOCS_TRUE@@HAVE_PDFLATEX_TRUE@ $(AM_V_SPHINX)$(SPHINXBUILD) -b latex -d $(SPHINXBUILDDIR)/doctrees/latex $(ALLSPHINXOPTS) $(SPHINXBUILDDIR)/latex +@HAVE_DOCS_TRUE@@HAVE_PDFLATEX_TRUE@ $(MAKE) -C $(SPHINXBUILDDIR)/latex all-pdf +@HAVE_DOCS_TRUE@@HAVE_PDFLATEX_TRUE@ @echo "The PDF documentation has been built in $(SPHINXBUILDDIR)/latex/" + +@HAVE_DOCS_TRUE@@HAVE_PDFLATEX_TRUE@install-pdf-local: +@HAVE_DOCS_TRUE@@HAVE_PDFLATEX_TRUE@ $(INSTALL) -d $(DESTDIR)/$(docdir) +@HAVE_DOCS_TRUE@@HAVE_PDFLATEX_TRUE@ $(INSTALL_DATA) $(SPHINXBUILDDIR)/latex/KnotDNS.pdf $(DESTDIR)/$(docdir)/ + +@HAVE_DOCS_TRUE@@HAVE_PDFLATEX_FALSE@pdf-local install-pdf-local: +@HAVE_DOCS_TRUE@@HAVE_PDFLATEX_FALSE@ @echo "Install 'pdflatex' and re-run configure to be able to generate PDF documentation!" + +@HAVE_DOCS_TRUE@man: $(man_MANS) +@HAVE_DOCS_TRUE@$(man_MANS)&: $(MANPAGES_RST) +@HAVE_DOCS_TRUE@ $(AM_V_SPHINX)$(SPHINXBUILD) -b man -d $(SPHINXBUILDDIR)/doctrees/man $(man_SPHINXOPTS) $(SPHINXBUILDDIR)/man +@HAVE_DOCS_TRUE@ @mkdir -p man +@HAVE_DOCS_TRUE@ @for f in $(SPHINXBUILDDIR)/man/*; do \ +@HAVE_DOCS_TRUE@ sed -e 's,[@]config_dir@,$(config_dir),' \ +@HAVE_DOCS_TRUE@ -e 's,[@]storage_dir@,$(storage_dir),' \ +@HAVE_DOCS_TRUE@ -e 's,[@]run_dir@,$(run_dir),' \ +@HAVE_DOCS_TRUE@ -e 's,[@]conf_mapsize@,$(conf_mapsize),' "$$f" > "man/$$(basename $$f)"; \ +@HAVE_DOCS_TRUE@ done + +@HAVE_DOCS_FALSE@html-local singlehtml pdf-local epub man install-html-local install-singlehtml install-pdf-local install-epub: +@HAVE_DOCS_FALSE@ @echo "Install 'sphinx-build' and re-run configure to be able to generate documentation!" clean-local: -rm -rf $(SPHINXBUILDDIR) - -rm -f man/*.1 man/*.5 man/*.8 + -rm -rf man # 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. diff --git a/doc/appendices.rst b/doc/appendices.rst index 309bb20..1012623 100644 --- a/doc/appendices.rst +++ b/doc/appendices.rst @@ -103,24 +103,3 @@ support. A command similar to the following may be used to verify what algorithms are supported: ``$ pkcs11-tool --modul /usr/lib64/pkcs11/libsofthsm2.so -M``. .. [#fn-utimaco] Requires setting the number of background workers to 1! - -The following table summarizes supported DNSSEC algorithm numbers and minimal -GnuTLS library version required. Any algorithm may work with older library, -however the supported operations may be limited (e.g. private key import). - -.. list-table:: - :header-rows: 1 - :stub-columns: 1 - - * - - - `Numbers <https://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml#dns-sec-alg-numbers-1>`_ - - GnuTLS version - * - ED25519 - - 15 - - 3.6.0 or newer - * - ECDSA - - 13, 14 - - 3.4.8 or newer - * - RSA - - 5, 7, 8, 10 - - 3.4.6 or newer diff --git a/doc/conf.py b/doc/conf.py index ec821d6..4b1c8e9 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -248,10 +248,7 @@ man_pages = [ # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) -texinfo_documents = [ - ('index', 'knot', 'Knot DNS Documentation', author, - 'KnotDNS', 'Knot Authoritative DNS Server', 'Miscellaneous') -] +#texinfo_documents = [] # Documents to append as an appendix to all manuals. #texinfo_appendices = [] diff --git a/doc/configuration.rst b/doc/configuration.rst index a29521b..982031b 100644 --- a/doc/configuration.rst +++ b/doc/configuration.rst @@ -377,6 +377,19 @@ which must be used for the transaction security:: - domain: example.net. acl: owner_rule3_net +.. _Handling CNAME and DNAME-related updates: + +Handling CNAME and DNAME-related updates +---------------------------------------- + +In general, no RR must exist beside a CNAME or below a DNAME. Whenever +such a CNAME or DNAME-related semantic rule is vialoated by an RR addition +in DDNS (this means addition of a CNAME beside an existing record, addition of +another record beside a CNAME, addition of a DNAME above an existing record, +addition of another record below a DNAME), such an RR addition is silently ignored. +However, other RRs from the same DDNS update are processed normally. This is slightly +non-compliant with RFC 6672 (in particular, no RR occlusion takes place). + .. _dnssec: Automatic DNSSEC signing @@ -826,7 +839,7 @@ of the used certificate: .. code-block:: console ... info: binding to QUIC interface ::1@853 - ... info: QUIC, certificate public key 0xtdayWpnJh4Py8goi8cei/gXGD4kJQ+HEqcxS++DBw= + ... info: QUIC/TLS, certificate public key 0xtdayWpnJh4Py8goi8cei/gXGD4kJQ+HEqcxS++DBw= .. TIP:: @@ -861,10 +874,10 @@ Using :doc:`kdig<man_kdig>` we can verify that the server responds over QUIC: ;; version.server. CH TXT ;; ANSWER SECTION: - version.server. 0 CH TXT "Knot DNS 3.3.0" + version.server. 0 CH TXT "Knot DNS 3.4.0" ;; Received 468 B - ;; Time 2023-08-15 15:04:36 CEST + ;; Time 2024-06-21 08:30:12 CEST ;; From ::1@853(QUIC) in 1.1 ms In this case, :rfc:`opportunistic authentication<9103#section-9.3.1>` was @@ -1074,6 +1087,62 @@ This mode is recommended if possible. Knot DNS uses certificate public key pinning. This approach has much lower overhead and in most cases simplifies configuration and certificate management. +.. _DNS_over_TLS: + +DNS over TLS +============ + +TLS is an encrypted internet transport protocol. +Knot DNS supports DNS over TLS (DoT) (:rfc:`7858`), including zone transfers (XoT). +By default, the TCP port `853` is used for DNS over TLS. + +There are the same requirements for TLS key and certificate as for :ref:`DNS_over_QUIC`. + +In order to listen for incoming requests over TLS, :ref:`interface<server_listen-tls>` +must be configured. + +An example of configuration of listening for DNS over TLS on the loopback interface: + +.. code-block:: console + + server: + listen-tls: ::1 + +When the server is started, it logs some interface details and public key pin +of the used certificate: + +.. code-block:: console + + ... info: binding to TLS interface ::1@853 + ... info: QUIC/TLS, certificate public key 0xtdayWpnJh4Py8goi8cei/gXGD4kJQ+HEqcxS++DBw= + +Using :doc:`kdig<man_kdig>` we can verify that the server responds over TLS: + +.. code-block:: console + + $ kdig @::1 ch txt version.server +tls + ;; TLS session (TLS1.3)-(ECDHE-X25519)-(EdDSA-Ed25519)-(AES-256-GCM) + ;; ->>HEADER<<- opcode: QUERY; status: NOERROR; id: 0 + ;; Flags: qr rd; QUERY: 1; ANSWER: 1; AUTHORITY: 0; ADDITIONAL: 1 + + ;; EDNS PSEUDOSECTION: + ;; Version: 0; flags: ; UDP size: 1232 B; ext-rcode: NOERROR + ;; PADDING: 370 B + + ;; QUESTION SECTION: + ;; version.server. CH TXT + + ;; ANSWER SECTION: + version.server. 0 CH TXT "Knot DNS 3.4.0" + + ;; Received 468 B + ;; Time 2024-06-21 08:31:13 CEST + ;; From ::1@853(TLS) in 9.1 ms + +Zone transfer configuration and authentication profiles are almost identical +to :ref:`DNS_over_QUIC`, with the only difference being the enabling of +:ref:`remote_tls` for the corresponding remotes. + .. _query-modules: Query modules diff --git a/doc/installation.rst b/doc/installation.rst index f89f439..8eebaa3 100644 --- a/doc/installation.rst +++ b/doc/installation.rst @@ -34,10 +34,7 @@ The build process relies on these standard tools: * autoconf >= 2.65 * python-sphinx (optional, for documentation building) -GCC >= 4.1 is mandatory for atomic built-ins, but the latest -available version is recommended. Another requirement is ``_GNU_SOURCE`` -and C99 support, otherwise it adapts to the available compiler features. -LLVM clang compiler since version 2.9 can be used as well. +A GCC or LLVM Clang compiler with C11 support. Getting the source code ----------------------- diff --git a/doc/introduction.rst b/doc/introduction.rst index 398d0d4..f472b85 100644 --- a/doc/introduction.rst +++ b/doc/introduction.rst @@ -29,7 +29,7 @@ DNS features: * Primary and secondary server operation * Internet (IN) and Chaos (CH) classes * DNS extension (EDNS0, EDE, EXPIRE) -* UDP, TCP, and QUIC protocols +* UDP, TCP, TLS 1.3, and QUIC protocols * Zone catalog generation and interpretation * Minimal responses * Dynamic zone updates @@ -73,7 +73,7 @@ Remarkable module extensions: Remarkable supported networking features: * TCP Fast Open (client and server) -* Opportunistic, strict, and mutual authentication profiles over QUIC +* Opportunistic, strict, and mutual authentication profiles over TLS 1.3 or QUIC * High-performance UDP, TCP, and QUIC through AF_XDP processing (on Linux 4.18+) * SO_REUSEPORT (on Linux) or SO_REUSEPORT_LB (on FreeBSD 12.0+) on UDP and by choice on TCP * Binding to non-local addresses (IP_FREEBIND on Linux, IP_BINDANY/IPV6_BINDANY on FreeBSD) diff --git a/doc/man/kcatalogprint.8in b/doc/man/kcatalogprint.8 index da964d8..f9d9fc9 100644 --- a/doc/man/kcatalogprint.8in +++ b/doc/man/kcatalogprint.8 @@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "KCATALOGPRINT" "8" "@RELEASE_DATE@" "@VERSION@" "Knot DNS" +.TH "KCATALOGPRINT" "8" "2024-09-02" "3.4.0" "Knot DNS" .SH NAME kcatalogprint \- Knot DNS catalog print utility .SH SYNOPSIS @@ -40,10 +40,10 @@ The program prints zone catalog stored in a catalog database. .INDENT 0.0 .TP \fB\-c\fP, \fB\-\-config\fP \fIfile\fP -Use a textual configuration file (default is \fB@config_dir@/knot.conf\fP). +Use a textual configuration file (default is \fB/usr/local/etc/knot/knot.conf\fP). .TP \fB\-C\fP, \fB\-\-confdb\fP \fIdirectory\fP -Use a binary configuration database directory (default is \fB@storage_dir@/confdb\fP). +Use a binary configuration database directory (default is \fB/usr/local/var/lib/knot/confdb\fP). The default configuration database, if exists, has a preference to the default configuration file. .TP @@ -63,7 +63,8 @@ Filter the output by member zone name. Print the program help. .TP \fB\-V\fP, \fB\-\-version\fP -Print the program version. +Print the program version. The option \fB\-VV\fP makes the program +print the compile time configuration summary. .UNINDENT .SH EXIT VALUES .sp diff --git a/doc/man/kdig.1in b/doc/man/kdig.1 index 99745c9..207c8c8 100644 --- a/doc/man/kdig.1in +++ b/doc/man/kdig.1 @@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "KDIG" "1" "@RELEASE_DATE@" "@VERSION@" "Knot DNS" +.TH "KDIG" "1" "2024-09-02" "3.4.0" "Knot DNS" .SH NAME kdig \- Advanced DNS lookup utility .SH SYNOPSIS @@ -43,16 +43,16 @@ which must precede \fIquery\fP specification. .SS Parameters .INDENT 0.0 .TP -\fIquery\fP +.B \fIquery\fP \fIname\fP | \fB\-q\fP \fIname\fP | \fB\-x\fP \fIaddress\fP | \fB\-G\fP \fItapfile\fP .TP -\fIcommon\-settings\fP, \fIsettings\fP +.B \fIcommon\-settings\fP, \fIsettings\fP [\fIquery_class\fP] [\fIquery_type\fP] [\fB@\fP\fIserver\fP]... [\fIoptions\fP] .TP -\fIname\fP +.B \fIname\fP Is a domain name that is to be looked up. .TP -\fIserver\fP +.B \fIserver\fP Is a domain name or an IPv4 or IPv6 address of the nameserver to send a query to. An additional port can be specified using address:port ([address]:port for IPv6 address), address@port, or address#port notation. A value which begins @@ -132,7 +132,8 @@ is provided, empty question section is set. An explicit \fIquery_type\fP specification. See possible values above. .TP \fB\-V\fP, \fB\-\-version\fP -Print the program version. +Print the program version. The option \fB\-VV\fP makes the program +print the compile time configuration summary. .TP \fB\-x\fP \fIaddress\fP Send a reverse (PTR) query for IPv4 or IPv6 \fIaddress\fP\&. The correct name, class @@ -302,7 +303,7 @@ Use QUIC (DNS\-over\-QUIC). Request the nameserver identifier (NSID). .TP \fB+\fP[\fBno\fP]\fBbufsize\fP=\fIB\fP -Set EDNS buffer size in bytes (default is 4096 bytes). +Set EDNS buffer size in bytes (default is 1232 bytes). .TP \fB+\fP[\fBno\fP]\fBpadding\fP[=\fIB\fP] Use EDNS(0) padding option to pad queries, optionally to a specific @@ -319,7 +320,7 @@ Align the query to B\-byte\-block message using the EDNS(0) padding option Set EDNS(0) client subnet SUBN=addr/prefix. .TP \fB+\fP[\fBno\fP]\fBedns\fP[=\fIN\fP] -Use EDNS version (default is 0). +Use EDNS version (default is 0). EDNS(0) is enabled by default. .TP \fB+\fP[\fBno\fP]\fBtimeout\fP=\fIT\fP Set the wait\-for\-reply interval in seconds (default is 5 seconds). This timeout @@ -354,7 +355,7 @@ Use JSON for output encoding (RFC 8427). .TP \fB+noidn\fP Disable the IDN transformation to ASCII and vice versa. IDN support depends -on libidn availability during project building! If used in \fIcommon\-settings\fP, +on libidn2 availability during project building! If used in \fIcommon\-settings\fP, all IDN transformations are disabled. If used in the individual query \fIsettings\fP, transformation from ASCII is disabled on output for the particular query. Note that IDN transformation does not preserve domain name letter case. diff --git a/doc/man/keymgr.8in b/doc/man/keymgr.8 index 020d854..a963df3 100644 --- a/doc/man/keymgr.8in +++ b/doc/man/keymgr.8 @@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "KEYMGR" "8" "@RELEASE_DATE@" "@VERSION@" "Knot DNS" +.TH "KEYMGR" "8" "2024-09-02" "3.4.0" "Knot DNS" .SH NAME keymgr \- Knot DNS key management utility .SH SYNOPSIS @@ -51,17 +51,17 @@ The database is backed by LMDB. .SS Parameters .INDENT 0.0 .TP -\fIzone_name\fP +.B \fIzone_name\fP Name of the zone the command is executed for. .UNINDENT .SS Config options .INDENT 0.0 .TP \fB\-c\fP, \fB\-\-config\fP \fIfile\fP -Use a textual configuration file (default is \fB@config_dir@/knot.conf\fP). +Use a textual configuration file (default is \fB/usr/local/etc/knot/knot.conf\fP). .TP \fB\-C\fP, \fB\-\-confdb\fP \fIdirectory\fP -Use a binary configuration database directory (default is \fB@storage_dir@/confdb\fP). +Use a binary configuration database directory (default is \fB/usr/local/var/lib/knot/confdb\fP). The default configuration database, if exists, has a preference to the default configuration file. .TP @@ -98,7 +98,8 @@ Force colorized output in the normal mode. Print the program help. .TP \fB\-V\fP, \fB\-\-version\fP -Print the program version. +Print the program version. The option \fB\-VV\fP makes the program +print the compile time configuration summary. .UNINDENT .sp \fBNOTE:\fP @@ -279,16 +280,16 @@ Key deleted. .SS Timestamps .INDENT 0.0 .TP -0 +.B 0 Zero timestamp means infinite future. .TP -\fIUNIX_time\fP +.B \fIUNIX_time\fP Positive number of seconds since 1970 UTC. .TP -\fIYYYYMMDDHHMMSS\fP +.B \fIYYYYMMDDHHMMSS\fP Date and time in this format without any punctuation. .TP -\fIrelative_timestamp\fP +.B \fIrelative_timestamp\fP A sign character (\fB+\fP, \fB\-\fP), a number, and an optional time unit (\fBy\fP, \fBmo\fP, \fBd\fP, \fBh\fP, \fBmi\fP, \fBs\fP). The default unit is one second. E.g. +1mi, \-2mo. @@ -296,7 +297,7 @@ E.g. +1mi, \-2mo. .SS Output timestamp formats .INDENT 0.0 .TP -(none) +.B (none) The timestamps are printed as UNIX timestamp. .TP \fBhuman\fP diff --git a/doc/man/khost.1in b/doc/man/khost.1 index 292f080..4cae5e9 100644 --- a/doc/man/khost.1in +++ b/doc/man/khost.1 @@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "KHOST" "1" "@RELEASE_DATE@" "@VERSION@" "Knot DNS" +.TH "KHOST" "1" "2024-09-02" "3.4.0" "Knot DNS" .SH NAME khost \- Simple DNS lookup utility .SH SYNOPSIS @@ -41,11 +41,11 @@ instead. .SS Parameters .INDENT 0.0 .TP -\fIname\fP +.B \fIname\fP Is a domain name that is to be looked up. If the \fIname\fP is IPv4 or IPv6 address the PTR query type is used. .TP -\fIserver\fP +.B \fIserver\fP Is a name or an address of the nameserver to send a query to. The address can be specified using [address]:port notation. If no server is specified, the servers from \fB/etc/resolv.conf\fP are used. @@ -80,7 +80,8 @@ Use the TCP protocol. Enable verbose output. .TP \fB\-V\fP, \fB\-\-version\fP -Print the program version. +Print the program version. The option \fB\-VV\fP makes the program +print the compile time configuration summary. .TP \fB\-w\fP Wait forever for the reply. diff --git a/doc/man/kjournalprint.8in b/doc/man/kjournalprint.8 index 2a1303a..4c17e36 100644 --- a/doc/man/kjournalprint.8in +++ b/doc/man/kjournalprint.8 @@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "KJOURNALPRINT" "8" "@RELEASE_DATE@" "@VERSION@" "Knot DNS" +.TH "KJOURNALPRINT" "8" "2024-09-02" "3.4.0" "Knot DNS" .SH NAME kjournalprint \- Knot DNS journal print utility .SH SYNOPSIS @@ -42,17 +42,17 @@ changes are colored for terminal. .SS Parameters .INDENT 0.0 .TP -\fIzone_name\fP +.B \fIzone_name\fP A name of the zone to print the history for. .UNINDENT .SS Config options .INDENT 0.0 .TP \fB\-c\fP, \fB\-\-config\fP \fIfile\fP -Use a textual configuration file (default is \fB@config_dir@/knot.conf\fP). +Use a textual configuration file (default is \fB/usr/local/etc/knot/knot.conf\fP). .TP \fB\-C\fP, \fB\-\-confdb\fP \fIdirectory\fP -Use a binary configuration database directory (default is \fB@storage_dir@/confdb\fP). +Use a binary configuration database directory (default is \fB/usr/local/var/lib/knot/confdb\fP). The default configuration database, if exists, has a preference to the default configuration file. .TP @@ -80,9 +80,6 @@ Debug mode brief output. \fB\-x\fP, \fB\-\-mono\fP Don\(aqt generate colorized output. .TP -\fB\-n\fP, \fB\-\-no\-color\fP -An alias for \fB\-x\fP\&. Use of this option is deprecated, it will be removed in the future. -.TP \fB\-X\fP, \fB\-\-color\fP Force colorized output. .TP @@ -90,7 +87,8 @@ Force colorized output. Print the program help. .TP \fB\-V\fP, \fB\-\-version\fP -Print the program version. +Print the program version. The option \fB\-VV\fP makes the program +print the compile time configuration summary. .UNINDENT .SH EXIT VALUES .sp diff --git a/doc/man/knot.conf.5in b/doc/man/knot.conf.5 index d091d15..dc6fe4a 100644 --- a/doc/man/knot.conf.5in +++ b/doc/man/knot.conf.5 @@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "KNOT.CONF" "5" "@RELEASE_DATE@" "@VERSION@" "Knot DNS" +.TH "KNOT.CONF" "5" "2024-09-02" "3.4.0" "Knot DNS" .SH NAME knot.conf \- Knot DNS configuration file .SH DESCRIPTION @@ -47,10 +47,11 @@ the following symbols: .IP \(bu 2 \fBBOOL\fP – Boolean value (\fBon\fP/\fBoff\fP or \fBtrue\fP/\fBfalse\fP) .IP \(bu 2 -\fBTIME\fP – Number of seconds, an integer with possible time multiplier suffix -(\fBs\fP ~ 1, \fBm\fP ~ 60, \fBh\fP ~ 3600 or \fBd\fP ~ 24 * 3600) +\fBTIME\fP – Number of seconds, an integer with a possible time multiplier suffix +(\fBs\fP ~ 1, \fBm\fP ~ 60, \fBh\fP ~ 3600, \fBd\fP ~ 24 * 3600, \fBw\fP ~ 7 * 24 * 3600, +\fBM\fP ~ 30 * 24 * 3600, \fBy\fP ~ 365 * 24 * 3600) .IP \(bu 2 -\fBSIZE\fP – Number of bytes, an integer with possible size multiplier suffix +\fBSIZE\fP – Number of bytes, an integer with a possible size multiplier suffix (\fBB\fP ~ 1, \fBK\fP ~ 1024, \fBM\fP ~ 1024^2 or \fBG\fP ~ 1024^3) .IP \(bu 2 \fBBASE64\fP – Base64 encoded string @@ -268,6 +269,7 @@ server: dbus\-init\-delay: TIME listen: ADDR[@INT] | STR ... listen\-quic: ADDR[@INT] ... + listen\-tls: ADDR[@INT] ... .ft P .fi .UNINDENT @@ -531,19 +533,15 @@ Maximum EDNS0 UDP payload size for IPv6. \fIDefault:\fP \fB1232\fP .SS key\-file .sp -Path to a server key PEM file which is used for DNS over QUIC communication. +Path to a server key PEM file which is used for DNS over QUIC/TLS communication. A non\-absolute path of a user specified key file is relative to the -\fB@config_dir@\fP directory. -.sp -Change of this parameter requires restart of the Knot server to take effect. +\fB/usr/local/etc/knot\fP directory. .sp \fIDefault:\fP auto\-generated key .SS cert\-file .sp -Path to a server certificate PEM file which is used for DNS over QUIC communication. -A non\-absolute path is relative to the \fB@config_dir@\fP directory. -.sp -Change of this parameter requires restart of the Knot server to take effect. +Path to a server certificate PEM file which is used for DNS over QUIC/TLS communication. +A non\-absolute path is relative to the \fB/usr/local/etc/knot\fP directory. .sp \fIDefault:\fP one\-time in\-memory certificate .SS edns\-client\-subnet @@ -604,20 +602,21 @@ catalog zones and their members) are loaded or successfully bootstrapped. the signal parameters are \fIzone name\fP and \fIzone SOA serial\fP\&. .IP \(bu 2 \fBkeys\-updated\fP \- The signal \fBkeys_updated\fP is emitted when a DNSSEC key set -of this zone is updated. +is updated; the signal parameter is \fIzone name\fP\&. .IP \(bu 2 \fBksk\-submission\fP – The signal \fBzone_ksk_submission\fP is emitted if there is a ready KSK present when the zone is signed; the signal parameters are \fIzone name\fP, \fIKSK keytag\fP, and \fIKSK KASP id\fP\&. .IP \(bu 2 \fBdnssec\-invalid\fP – The signal \fBzone_dnssec_invalid\fP is emitted when DNSSEC -validation fails; the signal parameter is \fIzone name\fP\&. +validation fails; the signal parameters are \fIzone name\fP, and \fIremaining seconds\fP +until an RRSIG expires. .UNINDENT .sp \fBNOTE:\fP .INDENT 0.0 .INDENT 3.5 -This function requires systemd version at least 221. +This function requires systemd version at least 221 or libdbus. .UNINDENT .UNINDENT .sp @@ -655,14 +654,14 @@ for incoming queries over QUIC protocol. Change of this parameter requires restart of the Knot server to take effect. .sp \fIDefault:\fP not set +.SS listen\-tls .sp -\fBNOTE:\fP -.INDENT 0.0 -.INDENT 3.5 -Incoming \fI\%DDNS\fP over QUIC isn\(aqt supported. -The server always responds with SERVFAIL. -.UNINDENT -.UNINDENT +One or more IP addresses (and optionally ports) where the server listens +for incoming queries over TLS protocol (DoT). +.sp +Change of this parameter requires restart of the Knot server to take effect. +.sp +\fIDefault:\fP not set .SH XDP SECTION .sp Various options related to XDP listening, especially TCP. @@ -684,6 +683,9 @@ xdp: tcp\-idle\-reset\-timeout: TIME tcp\-resend\-timeout: TIME route\-check: BOOL + ring\-size: INT + busypoll\-budget: INT + busypoll\-timeout: INT .ft P .fi .UNINDENT @@ -849,6 +851,63 @@ Only VLAN 802.1Q is supported. .UNINDENT .sp \fIDefault:\fP \fBoff\fP +.SS ring\-size +.sp +Size of RX, FQ, TX, and CQ rings. +.sp +Change of this parameter requires restart of the Knot server to take effect. +.sp +\fBNOTE:\fP +.INDENT 0.0 +.INDENT 3.5 +This value should be at least as high as the configured RX size of the +network device in the XDP mode. +.UNINDENT +.UNINDENT +.sp +\fIDefault:\fP \fB2048\fP +.SS busypoll\-budget +.sp +If set to a positive value, preferred busy polling is enabled with the +specified budget. +.sp +Change of this parameter requires restart of the Knot server to take effect. +.sp +\fBNOTE:\fP +.INDENT 0.0 +.INDENT 3.5 +Preferred busy polling also requires setting \fBnapi_defer_hard_irqs\fP and +\fBgro_flush_timeout\fP for the appropriate network interface. E.g.: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +echo 2 | sudo tee /sys/class/net/<interface>/napi_defer_hard_irqs +echo 200000 | sudo tee /sys/class/net/<interface>/gro_flush_timeout +.ft P +.fi +.UNINDENT +.UNINDENT +.UNINDENT +.UNINDENT +.sp +\fBNOTE:\fP +.INDENT 0.0 +.INDENT 3.5 +A recommended value is between 8 and 64. +.UNINDENT +.UNINDENT +.sp +\fIDefault:\fP \fB0\fP (disabled) +.SS busypoll\-timeout +.sp +Timeout in microseconds of preferrred busy polling if enabled by +\fI\%busypoll\-budget\fP\&. +.sp +Change of this parameter requires restart of the Knot server to take effect. +.sp +\fIDefault:\fP \fB20\fP (20 microseconds) .SH CONTROL SECTION .sp Configuration of the server control interface. @@ -1266,6 +1325,7 @@ remote: address: ADDR[@INT] | STR ... via: ADDR[@INT] ... quic: BOOL + tls: BOOL key: key_id cert\-key: BASE64 ... block\-notify\-after\-transfer: BOOL @@ -1356,6 +1416,12 @@ queried remotes. .UNINDENT .sp \fIDefault:\fP \fBoff\fP +.SS tls +.sp +If this option is set, the TLS (DoT) protocol will be used for outgoing communication +with this remote. +.sp +\fIDefault:\fP \fBoff\fP .SS key .sp A \fI\%reference\fP to the TSIG key which is used to authenticate @@ -1787,8 +1853,6 @@ Possible values: \fBNOTE:\fP .INDENT 0.0 .INDENT 3.5 -Ed25519 algorithm is only available if compiled with GnuTLS 3.6.0+. -.sp Ed448 algorithm is only available if compiled with GnuTLS 3.6.12+ and Nettle 3.6+. .UNINDENT .UNINDENT @@ -1955,6 +2019,10 @@ will be refreshed, in order to prevent expired RRSIGs on secondary servers or resolvers\(aq caches. .sp \fIDefault:\fP 0.1 * \fI\%rrsig\-lifetime\fP + \fI\%propagation\-delay\fP + \fI\%zone\-max\-ttl\fP +.sp +If \fI\%dnssec\-validation\fP is enabled: +.sp +\fIDefault:\fP \fB1d\fP (1 day) .SS rrsig\-pre\-refresh .sp A period (in seconds) how long at most before a signature refresh time the signature @@ -2638,7 +2706,9 @@ Every NSEC(3) RR is linked to the lexicographically next one. .sp The validation is not affected by \fI\%dnssec\-policy\fP configuration, except for \fI\%signing\-threads\fP option, which specifies the number -of threads for parallel validation. +of threads for parallel validation, and \fI\%rrsig\-refresh\fP, which +defines minimal allowed remaining RRSIG validity (otherwise a warning is +logged). .sp \fBNOTE:\fP .INDENT 0.0 diff --git a/doc/man/knotc.8in b/doc/man/knotc.8 index 01bfc95..5e41e97 100644 --- a/doc/man/knotc.8in +++ b/doc/man/knotc.8 @@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "KNOTC" "8" "@RELEASE_DATE@" "@VERSION@" "Knot DNS" +.TH "KNOTC" "8" "2024-09-02" "3.4.0" "Knot DNS" .SH NAME knotc \- Knot DNS control utility .SH SYNOPSIS @@ -43,10 +43,10 @@ is executed in the interactive mode. .INDENT 0.0 .TP \fB\-c\fP, \fB\-\-config\fP \fIfile\fP -Use a textual configuration file (default is \fB@config_dir@/knot.conf\fP). +Use a textual configuration file (default is \fB/usr/local/etc/knot/knot.conf\fP). .TP \fB\-C\fP, \fB\-\-confdb\fP \fIdirectory\fP -Use a binary configuration database directory (default is \fB@storage_dir@/confdb\fP). +Use a binary configuration database directory (default is \fB/usr/local/var/lib/knot/confdb\fP). The default configuration database, if exists, has a preference to the default configuration file. .UNINDENT @@ -55,10 +55,10 @@ configuration file. .TP \fB\-m\fP, \fB\-\-max\-conf\-size\fP \fIMiB\fP Set maximum size of the configuration database -(default is @conf_mapsize@ MiB, maximum 10000 MiB). +(default is 500 MiB, maximum 10000 MiB). .TP \fB\-s\fP, \fB\-\-socket\fP \fIpath\fP -Use a control UNIX socket path (default is \fB@run_dir@/knot.sock\fP). +Use a control UNIX socket path (default is \fB/usr/local/var/run/knot/knot.sock\fP). .TP \fB\-t\fP, \fB\-\-timeout\fP \fIseconds\fP Use a control timeout in seconds. Set to 0 for infinity (default is 60). @@ -88,7 +88,8 @@ Enable debug output. Print the program help. .TP \fB\-V\fP, \fB\-\-version\fP -Print the program version. +Print the program version. The option \fB\-VV\fP makes the program +print the compile time configuration summary. .UNINDENT .SS Actions .INDENT 0.0 @@ -173,8 +174,9 @@ disables all other filters by default, but they can still be turned on explicitly. If zone flushing is disabled, the original zone file is backed up instead of writing out zone contents to a file. When backing\-up a catalog zone, it is recommended to prevent ongoing changes to it by use of -\fBzone\-freeze\fP\&. -See \fI\%Notes\fP below about the directory permissions. (#) +\fBzone\-freeze\fP\&. The force option allows an already existing backupdir to +be overwritten. See \fI\%Notes\fP below about the directory permissions. +(#) .TP \fBzone\-restore\fP [\fIzone\fP\&...] \fB+backupdir\fP \fIdirectory\fP [\fIfilter\fP\&...] Trigger a zone data and metadata restore from a specified backup directory. @@ -187,6 +189,10 @@ permissions. (#) Trigger a DNSSEC re\-sign of the zone. Existing signatures will be dropped. This command is valid for zones with DNSSEC signing enabled. (#) .TP +\fBzone\-validate\fP [\fIzone\fP\&...] +Trigger a DNSSEC validation of the zone. If the validation fails and the +zone is secondary, the zone expires immediately! (#) +.TP \fBzone\-keys\-load\fP [\fIzone\fP\&...] Trigger a load of DNSSEC keys and other signing material from KASP database (which might have been altered manually). If suitable, re\-sign the zone @@ -207,7 +213,8 @@ KSK in submission phase and the old KSK can be retired. (#) \fBzone\-freeze\fP [\fIzone\fP\&...] Trigger a zone freeze. All running events will be finished and all new and pending (planned) zone\-changing events (load, refresh, update, flush, and DNSSEC signing) -will be held up until the zone is thawed. (#) +will be held up until the zone is thawed. Up to 8 (this limit is hardcoded) DDNS +updates per zone will be queued, subsequent updates will be refused. (#) .TP \fBzone\-thaw\fP [\fIzone\fP\&...] Trigger dismissal of zone freeze. (#) diff --git a/doc/man/knotd.8in b/doc/man/knotd.8 index 1d02cc8..bbeb6a4 100644 --- a/doc/man/knotd.8in +++ b/doc/man/knotd.8 @@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "KNOTD" "8" "@RELEASE_DATE@" "@VERSION@" "Knot DNS" +.TH "KNOTD" "8" "2024-09-02" "3.4.0" "Knot DNS" .SH NAME knotd \- Knot DNS server daemon .SH SYNOPSIS @@ -41,10 +41,10 @@ the DNS server daemon. .INDENT 0.0 .TP \fB\-c\fP, \fB\-\-config\fP \fIfile\fP -Use a textual configuration file (default is \fB@config_dir@/knot.conf\fP). +Use a textual configuration file (default is \fB/usr/local/etc/knot/knot.conf\fP). .TP \fB\-C\fP, \fB\-\-confdb\fP \fIdirectory\fP -Use a binary configuration database directory (default is \fB@storage_dir@/confdb\fP). +Use a binary configuration database directory (default is \fB/usr/local/var/lib/knot/confdb\fP). The default configuration database, if exists, has a preference to the default configuration file. .UNINDENT @@ -53,10 +53,10 @@ configuration file. .TP \fB\-m\fP, \fB\-\-max\-conf\-size\fP \fIMiB\fP Set maximum size of the configuration database -(default is @conf_mapsize@ MiB, maximum 10000 MiB). +(default is 500 MiB, maximum 10000 MiB). .TP \fB\-s\fP, \fB\-\-socket\fP \fIpath\fP -Use a remote control UNIX socket path (default is \fB@run_dir@/knot.sock\fP). +Use a remote control UNIX socket path (default is \fB/usr/local/var/run/knot/knot.sock\fP). .TP \fB\-d\fP, \fB\-\-daemonize\fP [\fIdirectory\fP] Run the server as a daemon. New root directory may be specified @@ -69,7 +69,8 @@ Enable debug output. Print the program help. .TP \fB\-V\fP, \fB\-\-version\fP -Print the program version. +Print the program version. The option \fB\-VV\fP makes the program +print the compile time configuration summary. .UNINDENT .SS Signals .sp diff --git a/doc/man/knsec3hash.1in b/doc/man/knsec3hash.1 index d9fa4a3..3bb9766 100644 --- a/doc/man/knsec3hash.1in +++ b/doc/man/knsec3hash.1 @@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "KNSEC3HASH" "1" "@RELEASE_DATE@" "@VERSION@" "Knot DNS" +.TH "KNSEC3HASH" "1" "2024-09-02" "3.4.0" "Knot DNS" .SH NAME knsec3hash \- Simple utility to compute NSEC3 hash .SH SYNOPSIS @@ -35,27 +35,39 @@ knsec3hash \- Simple utility to compute NSEC3 hash \fBknsec3hash\fP \fIsalt\fP \fIalgorithm\fP \fIiterations\fP \fIname\fP .sp \fBknsec3hash\fP \fIalgorithm\fP \fIflags\fP \fIiterations\fP \fIsalt\fP \fIname\fP +.sp +\fBknsec3hash\fP [\fI\-h\fP] [\fI\-V\fP] .SH DESCRIPTION .sp This utility generates a NSEC3 hash for a given domain name and parameters of NSEC3 hash. .SS Parameters .INDENT 0.0 .TP -\fIsalt\fP +.B \fIsalt\fP Specifies a binary salt encoded as a hexadecimal string. .TP -\fIalgorithm\fP +.B \fIalgorithm\fP Specifies a hashing algorithm by number. Currently, the only supported algorithm is SHA\-1 (number 1). .TP -\fIiterations\fP +.B \fIiterations\fP Specifies the number of additional iterations of the hashing algorithm. .TP -\fIname\fP +.B \fIname\fP Specifies the domain name to be hashed. .TP -\fIflags\fP +.B \fIflags\fP Specifies NSEC3 flags as an unsigned integer. .UNINDENT +.SS Options +.INDENT 0.0 +.TP +\fB\-h\fP, \fB\-\-help\fP +Print the program help. +.TP +\fB\-V\fP, \fB\-\-version\fP +Print the program version. The option \fB\-VV\fP makes the program +print the compile time configuration summary. +.UNINDENT .SH EXIT VALUES .sp Exit status of 0 means successful operation. Any other exit status indicates diff --git a/doc/man/knsupdate.1in b/doc/man/knsupdate.1 index ed34dd2..58220a0 100644 --- a/doc/man/knsupdate.1in +++ b/doc/man/knsupdate.1 @@ -27,12 +27,14 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "KNSUPDATE" "1" "@RELEASE_DATE@" "@VERSION@" "Knot DNS" +.TH "KNSUPDATE" "1" "2024-09-02" "3.4.0" "Knot DNS" .SH NAME knsupdate \- Dynamic DNS update utility .SH SYNOPSIS .sp -\fBknsupdate\fP [\fIoptions\fP] [\fIfilename\fP] +\fBknsupdate\fP [\fB\-v\fP] [\fIoptions\fP] [\fIfilename\fP] +.sp +\fBknsupdate\fP [\fB\-q\fP] [\fIquic_options\fP] [\fIoptions\fP] [\fIfilename\fP] .SH DESCRIPTION .sp This utility sends Dynamic DNS update messages to a DNS server. Update content @@ -45,44 +47,76 @@ comments and are not processed. .SS Parameters .INDENT 0.0 .TP -\fIfilename\fP +.B \fIfilename\fP Path to the file with knsupdate commands. .UNINDENT .SS Options .INDENT 0.0 .TP -\fB\-d\fP -Enable debug messages. +\fB\-T\fP, \fB\-\-tcp\fP +Use a TCP connection. (\fB\-v\fP can be used for compatibility with nsupdate). .TP -\fB\-h\fP, \fB\-\-help\fP -Print the program help. +\fB\-S\fP, \fB\-\-tls\fP +Use a TLS connection. .TP -\fB\-k\fP \fIkeyfile\fP -Use the TSIG key stored in a file \fIkeyfile\fP to authenticate the request. The -file should contain the key in the same format, which is accepted by the -\fB\-y\fP option. +\fB\-Q\fP, \fB\-\-quic\fP +Use a QUIC connection. .TP -\fB\-p\fP \fIport\fP +\fB\-p\fP, \fB\-\-port\fP \fInumber\fP Set the port to use for connections to the server (if not explicitly specified -in the update). The default is 53. +in the update). The default is 53 for UDP/TCP or 853 for QUIC. .TP -\fB\-r\fP \fIretries\fP +\fB\-r\fP, \fB\-\-retry\fP \fIcount\fP The number of retries for UDP requests. The default is 3. .TP -\fB\-t\fP \fItimeout\fP +\fB\-t\fP, \fB\-\-timeout\fP \fIseconds\fP The total timeout (for all UDP update tries) of the update request in seconds. The default is 12. If set to zero, the timeout is infinite. .TP -\fB\-v\fP -Use a TCP connection. -.TP -\fB\-V\fP, \fB\-\-version\fP -Print the program version. -.TP -\fB\-y\fP [\fIalg\fP:]\fIname\fP:\fIkey\fP +\fB\-y\fP, \fB\-\-tsig\fP [\fIalg\fP:]\fIname\fP:\fIkey\fP Use the TSIG key with a name \fIname\fP to authenticate the request. The \fIalg\fP part specifies the algorithm (the default is hmac\-sha256) and \fIkey\fP specifies the shared secret encoded in Base64. +.TP +\fB\-k\fP, \fB\-\-tsigfile\fP \fIpath\fP +Use the TSIG key stored in a file \fIkeyfile\fP to authenticate the request. The +file should contain the key in the same format, which is accepted by the +\fB\-y\fP option. +.TP +\fB\-d\fP, \fB\-\-debug\fP +Enable debug messages. +.TP +\fB\-h\fP, \fB\-\-help\fP +Print the program help. +.TP +\fB\-V\fP, \fB\-\-version\fP +Print the program version. The option \fB\-VV\fP makes the program +print the compile time configuration summary. +.UNINDENT +.SS QUIC/TLS options +.INDENT 0.0 +.TP +\fB\-H\fP, \fB\-\-hostname\fP \fIstring\fP +Enable remote server hostname validation. +.TP +\fB\-P\fP, \fB\-\-pin\fP \fIbase64\fP +Use Out\-of\-Band key\-pinned privacy profile +(RFC 7858#section\-4.2). The PIN must be a Base64 encoded SHA\-256 hash of the +X.509 SubjectPublicKeyInfo. Can be specified multiple times. +.TP +\fB\-A\fP, \fB\-\-ca\fP [\fIpath\fP] +Enable certificate validation. Certification authority certificates +are loaded from the specified PEM file (default is system certificate storage +if no argument is provided). Can be specified multiple times. +.TP +\fB\-E\fP, \fB\-\-certfile\fP \fIpath\fP +Path to a client certificate file. +.TP +\fB\-K\fP, \fB\-\-keyfile\fP \fIpath\fP +Path to a client key file. +.TP +\fB\-s\fP, \fB\-\-sni\fP \fIstring\fP +Use specified Server Name Indication. .UNINDENT .SS Commands .INDENT 0.0 diff --git a/doc/man/kxdpgun.8in b/doc/man/kxdpgun.8 index f93872b..d7892eb 100644 --- a/doc/man/kxdpgun.8in +++ b/doc/man/kxdpgun.8 @@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "KXDPGUN" "8" "@RELEASE_DATE@" "@VERSION@" "Knot DNS" +.TH "KXDPGUN" "8" "2024-09-02" "3.4.0" "Knot DNS" .SH NAME kxdpgun \- XDP-powered DNS benchmarking tool .SH SYNOPSIS @@ -47,10 +47,10 @@ configured for the network interface. .SS Parameters .INDENT 0.0 .TP -\fIfilename\fP +.B \fIfilename\fP Path to the queries file. See the description below regarding the file format. .TP -\fItarget\fP +.B \fItarget\fP Either the domain name, IPv4 or IPv6 address of a remote target. .UNINDENT .SS Options @@ -90,6 +90,11 @@ CPU ID increment for next thread (default is 0s1). \fB\-i\fP, \fB\-\-infile\fP \fIfilename\fP Path to a file with query templates. .TP +\fB\-B\fP, \fB\-\-binary\fP +Specify that input file is in binary format. This format is similar to the +TCP DNS message format. The file contains records formated as 2\-octet length +(network order) followed by a message in DNS wire format. +.TP \fB\-I\fP, \fB\-\-interface\fP \fIinterface\fP Network interface for outgoing communication. This can be useful in situations when the interfaces are in a bond for example. @@ -136,11 +141,20 @@ has to exist. This option is ignored if not in the QUIC mode. The recommended usage is with \fB\-\-quic=R\fP or with low QPS. Otherwise, too many files are generated. .TP +\fB\-j\fP, \fB\-\-json\fP +Print statistics formatted as json. +.TP +\fB\-S\fP, \fB\-\-stats\-period\fP \fIperiod\fP +Report statistics automatically every \fIperiod\fP milliseconds. +.sp +These reports contain only metrics collected in the given period. +.TP \fB\-h\fP, \fB\-\-help\fP Print the program help. .TP \fB\-V\fP, \fB\-\-version\fP -Print the program version. +Print the program version. The option \fB\-VV\fP makes the program +print the compile time configuration summary. .UNINDENT .SS Queries file format .sp @@ -187,7 +201,8 @@ Instead of opening a connection for each query, reuse connections. .SS Signals .sp Sending USR1 signal to a running process triggers current statistics dump -to the standard output. +to the standard output. In combination with \fB\-S\fP may cause erratic printout +timing. .SH NOTES .sp Linux kernel 4.18+ is required. @@ -197,6 +212,12 @@ CAP_NET_RAW, CAP_NET_ADMIN, CAP_SYS_ADMIN, CAP_IPC_LOCK, and CAP_SYS_RESOURCE (Linux < 5.11). .sp The utility allocates source UDP/TCP ports from the range 2000\-65535. +.sp +Due to the multi\-threaded program structure there are slight discrepancies in +the timespan during which metrics are collected for any given thread. The +statistics printouts ignore this and are thus ever\-so\-slightly inaccurate. The +error margin decreases proportionally to the volume of data & timespan over +which they are collected. .SH EXIT VALUES .sp Exit status of 0 means successful operation. Any other exit status indicates diff --git a/doc/man/kzonecheck.1in b/doc/man/kzonecheck.1 index a73b66e..22ebe47 100644 --- a/doc/man/kzonecheck.1in +++ b/doc/man/kzonecheck.1 @@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "KZONECHECK" "1" "@RELEASE_DATE@" "@VERSION@" "Knot DNS" +.TH "KZONECHECK" "1" "2024-09-02" "3.4.0" "Knot DNS" .SH NAME kzonecheck \- Knot DNS zone check tool .SH SYNOPSIS @@ -44,7 +44,7 @@ Please, refer to the \fBsemantic\-checks\fP configuration option in .SS Parameters .INDENT 0.0 .TP -\fIfilename\fP +.B \fIfilename\fP Path to the zone file to be checked. For reading from \fBstdin\fP use \fB/dev/stdin\fP or just \fB\-\fP\&. .UNINDENT @@ -77,7 +77,8 @@ Enable debug output. Print the program help. .TP \fB\-V\fP, \fB\-\-version\fP -Print the program version. +Print the program version. The option \fB\-VV\fP makes the program +print the compile time configuration summary. .UNINDENT .SH EXIT VALUES .sp diff --git a/doc/man/kzonesign.1in b/doc/man/kzonesign.1 index 147e112..558c95b 100644 --- a/doc/man/kzonesign.1in +++ b/doc/man/kzonesign.1 @@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "KZONESIGN" "1" "@RELEASE_DATE@" "@VERSION@" "Knot DNS" +.TH "KZONESIGN" "1" "2024-09-02" "3.4.0" "Knot DNS" .SH NAME kzonesign \- DNSSEC signing utility .SH SYNOPSIS @@ -43,17 +43,17 @@ and zone.adjust\-threads). .SS Parameters .INDENT 0.0 .TP -\fIzone_name\fP +.B \fIzone_name\fP A name of the zone to be signed. .UNINDENT .SS Config options .INDENT 0.0 .TP \fB\-c\fP, \fB\-\-config\fP \fIfile\fP -Use a textual configuration file (default is \fB@config_dir@/knot.conf\fP). +Use a textual configuration file (default is \fB/usr/local/etc/knot/knot.conf\fP). .TP \fB\-C\fP, \fB\-\-confdb\fP \fIdirectory\fP -Use a binary configuration database directory (default is \fB@storage_dir@/confdb\fP). +Use a binary configuration database directory (default is \fB/usr/local/var/lib/knot/confdb\fP). The default configuration database, if exists, has a preference to the default configuration file. .UNINDENT @@ -78,7 +78,8 @@ specified by timestamp. Print the program help. .TP \fB\-V\fP, \fB\-\-version\fP -Print the program version. +Print the program version. The option \fB\-VV\fP makes the program +print the compile time configuration summary. .UNINDENT .SH EXIT VALUES .sp diff --git a/doc/man_kcatalogprint.rst b/doc/man_kcatalogprint.rst index cccc641..da2ed97 100644 --- a/doc/man_kcatalogprint.rst +++ b/doc/man_kcatalogprint.rst @@ -40,7 +40,8 @@ Options Print the program help. **-V**, **--version** - Print the program version. + Print the program version. The option **-VV** makes the program + print the compile time configuration summary. Exit values ----------- diff --git a/doc/man_kdig.rst b/doc/man_kdig.rst index 4457b68..cda3303 100644 --- a/doc/man_kdig.rst +++ b/doc/man_kdig.rst @@ -111,7 +111,8 @@ Options An explicit *query_type* specification. See possible values above. **-V**, **--version** - Print the program version. + Print the program version. The option **-VV** makes the program + print the compile time configuration summary. **-x** *address* Send a reverse (PTR) query for IPv4 or IPv6 *address*. The correct name, class @@ -281,7 +282,7 @@ Options Request the nameserver identifier (NSID). **+**\ [\ **no**\ ]\ **bufsize**\ =\ *B* - Set EDNS buffer size in bytes (default is 4096 bytes). + Set EDNS buffer size in bytes (default is 1232 bytes). **+**\ [\ **no**\ ]\ **padding**\[\ =\ *B*\] Use EDNS(0) padding option to pad queries, optionally to a specific @@ -298,7 +299,7 @@ Options Set EDNS(0) client subnet SUBN=addr/prefix. **+**\ [\ **no**\ ]\ **edns**\[\ =\ *N*\] - Use EDNS version (default is 0). + Use EDNS version (default is 0). EDNS(0) is enabled by default. **+**\ [\ **no**\ ]\ **timeout**\ =\ *T* Set the wait-for-reply interval in seconds (default is 5 seconds). This timeout @@ -333,7 +334,7 @@ Options **+noidn** Disable the IDN transformation to ASCII and vice versa. IDN support depends - on libidn availability during project building! If used in *common-settings*, + on libidn2 availability during project building! If used in *common-settings*, all IDN transformations are disabled. If used in the individual query *settings*, transformation from ASCII is disabled on output for the particular query. Note that IDN transformation does not preserve domain name letter case. diff --git a/doc/man_keymgr.rst b/doc/man_keymgr.rst index 136a92c..a0001fe 100644 --- a/doc/man_keymgr.rst +++ b/doc/man_keymgr.rst @@ -75,7 +75,8 @@ Options Print the program help. **-V**, **--version** - Print the program version. + Print the program version. The option **-VV** makes the program + print the compile time configuration summary. .. NOTE:: Keymgr runs with the same user privileges as configured for :doc:`knotd<man_knotd>`. diff --git a/doc/man_khost.rst b/doc/man_khost.rst index 1fcc0bf..9447856 100644 --- a/doc/man_khost.rst +++ b/doc/man_khost.rst @@ -57,7 +57,8 @@ Options Enable verbose output. **-V**, **--version** - Print the program version. + Print the program version. The option **-VV** makes the program + print the compile time configuration summary. **-w** Wait forever for the reply. diff --git a/doc/man_kjournalprint.rst b/doc/man_kjournalprint.rst index f83a137..3b2d024 100644 --- a/doc/man_kjournalprint.rst +++ b/doc/man_kjournalprint.rst @@ -57,9 +57,6 @@ Options **-x**, **--mono** Don't generate colorized output. -**-n**, **--no-color** - An alias for **-x**. Use of this option is deprecated, it will be removed in the future. - **-X**, **--color** Force colorized output. @@ -67,7 +64,8 @@ Options Print the program help. **-V**, **--version** - Print the program version. + Print the program version. The option **-VV** makes the program + print the compile time configuration summary. Exit values ----------- diff --git a/doc/man_knotc.rst b/doc/man_knotc.rst index d03bc77..4755a6a 100644 --- a/doc/man_knotc.rst +++ b/doc/man_knotc.rst @@ -65,7 +65,8 @@ Options Print the program help. **-V**, **--version** - Print the program version. + Print the program version. The option **-VV** makes the program + print the compile time configuration summary. Actions ....... @@ -150,8 +151,9 @@ Actions explicitly. If zone flushing is disabled, the original zone file is backed up instead of writing out zone contents to a file. When backing-up a catalog zone, it is recommended to prevent ongoing changes to it by use of - **zone-freeze**. - See :ref:`Notes<notes>` below about the directory permissions. (#) + **zone-freeze**. The force option allows an already existing backupdir to + be overwritten. See :ref:`Notes<notes>` below about the directory permissions. + (#) **zone-restore** [*zone*...] **+backupdir** *directory* [*filter*...] Trigger a zone data and metadata restore from a specified backup directory. @@ -164,6 +166,10 @@ Actions Trigger a DNSSEC re-sign of the zone. Existing signatures will be dropped. This command is valid for zones with DNSSEC signing enabled. (#) +**zone-validate** [*zone*...] + Trigger a DNSSEC validation of the zone. If the validation fails and the + zone is secondary, the zone expires immediately! (#) + **zone-keys-load** [*zone*...] Trigger a load of DNSSEC keys and other signing material from KASP database (which might have been altered manually). If suitable, re-sign the zone @@ -184,7 +190,8 @@ Actions **zone-freeze** [*zone*...] Trigger a zone freeze. All running events will be finished and all new and pending (planned) zone-changing events (load, refresh, update, flush, and DNSSEC signing) - will be held up until the zone is thawed. (#) + will be held up until the zone is thawed. Up to 8 (this limit is hardcoded) DDNS + updates per zone will be queued, subsequent updates will be refused. (#) **zone-thaw** [*zone*...] Trigger dismissal of zone freeze. (#) diff --git a/doc/man_knotd.rst b/doc/man_knotd.rst index d0fe83b..9f3193f 100644 --- a/doc/man_knotd.rst +++ b/doc/man_knotd.rst @@ -46,7 +46,8 @@ Options Print the program help. **-V**, **--version** - Print the program version. + Print the program version. The option **-VV** makes the program + print the compile time configuration summary. Signals ....... diff --git a/doc/man_knsec3hash.rst b/doc/man_knsec3hash.rst index bf0688c..b3367fe 100644 --- a/doc/man_knsec3hash.rst +++ b/doc/man_knsec3hash.rst @@ -10,6 +10,8 @@ Synopsis :program:`knsec3hash` *algorithm* *flags* *iterations* *salt* *name* +:program:`knsec3hash` [*-h*] [*-V*] + Description ----------- @@ -33,6 +35,16 @@ Parameters *flags* Specifies NSEC3 flags as an unsigned integer. +Options +....... + +**-h**, **--help** + Print the program help. + +**-V**, **--version** + Print the program version. The option **-VV** makes the program + print the compile time configuration summary. + Exit values ----------- diff --git a/doc/man_knsupdate.rst b/doc/man_knsupdate.rst index 40a419b..e2d71f9 100644 --- a/doc/man_knsupdate.rst +++ b/doc/man_knsupdate.rst @@ -6,7 +6,9 @@ Synopsis -------- -:program:`knsupdate` [*options*] [*filename*] +:program:`knsupdate` [**-v**] [*options*] [*filename*] + +:program:`knsupdate` [**-q**] [*quic_options*] [*options*] [*filename*] Description ----------- @@ -28,39 +30,71 @@ Parameters Options ....... -**-d** - Enable debug messages. +**-T**, **--tcp** + Use a TCP connection. (**-v** can be used for compatibility with nsupdate). -**-h**, **--help** - Print the program help. +**-S**, **--tls** + Use a TLS connection. -**-k** *keyfile* - Use the TSIG key stored in a file *keyfile* to authenticate the request. The - file should contain the key in the same format, which is accepted by the - **-y** option. +**-Q**, **--quic** + Use a QUIC connection. -**-p** *port* +**-p**, **--port** *number* Set the port to use for connections to the server (if not explicitly specified - in the update). The default is 53. + in the update). The default is 53 for UDP/TCP or 853 for QUIC. -**-r** *retries* +**-r**, **--retry** *count* The number of retries for UDP requests. The default is 3. -**-t** *timeout* +**-t**, **--timeout** *seconds* The total timeout (for all UDP update tries) of the update request in seconds. The default is 12. If set to zero, the timeout is infinite. -**-v** - Use a TCP connection. - -**-V**, **--version** - Print the program version. - -**-y** [*alg*:]\ *name*:*key* +**-y**, **--tsig** [*alg*:]\ *name*:*key* Use the TSIG key with a name *name* to authenticate the request. The *alg* part specifies the algorithm (the default is hmac-sha256) and *key* specifies the shared secret encoded in Base64. +**-k**, **--tsigfile** *path* + Use the TSIG key stored in a file *keyfile* to authenticate the request. The + file should contain the key in the same format, which is accepted by the + **-y** option. + +**-d**, **--debug** + Enable debug messages. + +**-h**, **--help** + Print the program help. + +**-V**, **--version** + Print the program version. The option **-VV** makes the program + print the compile time configuration summary. + +QUIC/TLS options +................ + +**-H**, **--hostname** *string* + Enable remote server hostname validation. + +**-P**, **--pin** *base64* + Use Out-of-Band key-pinned privacy profile + (RFC 7858#section-4.2). The PIN must be a Base64 encoded SHA-256 hash of the + X.509 SubjectPublicKeyInfo. Can be specified multiple times. + +**-A**, **--ca** [*path*] + Enable certificate validation. Certification authority certificates + are loaded from the specified PEM file (default is system certificate storage + if no argument is provided). Can be specified multiple times. + +**-E**, **--certfile** *path* + Path to a client certificate file. + +**-K**, **--keyfile** *path* + Path to a client key file. + +**-s**, **--sni** *string* + Use specified Server Name Indication. + Commands ........ diff --git a/doc/man_kxdpgun.rst b/doc/man_kxdpgun.rst index 28713ba..bc26d12 100644 --- a/doc/man_kxdpgun.rst +++ b/doc/man_kxdpgun.rst @@ -67,6 +67,11 @@ Options **-i**, **--infile** *filename* Path to a file with query templates. +**-B**, **--binary** + Specify that input file is in binary format. This format is similar to the + TCP DNS message format. The file contains records formated as 2-octet length + (network order) followed by a message in DNS wire format. + **-I**, **--interface** *interface* Network interface for outgoing communication. This can be useful in situations when the interfaces are in a bond for example. @@ -111,11 +116,20 @@ Options This option is ignored if not in the QUIC mode. The recommended usage is with **--quic=R** or with low QPS. Otherwise, too many files are generated. +**-j**, **--json** + Print statistics formatted as json. + +**-S**, **--stats-period** *period* + Report statistics automatically every *period* milliseconds. + + These reports contain only metrics collected in the given period. + **-h**, **--help** Print the program help. **-V**, **--version** - Print the program version. + Print the program version. The option **-VV** makes the program + print the compile time configuration summary. Queries file format ................... @@ -165,7 +179,8 @@ Signals ....... Sending USR1 signal to a running process triggers current statistics dump -to the standard output. +to the standard output. In combination with **-S** may cause erratic printout +timing. Notes ----- @@ -178,6 +193,12 @@ CAP_NET_RAW, CAP_NET_ADMIN, CAP_SYS_ADMIN, CAP_IPC_LOCK, and CAP_SYS_RESOURCE The utility allocates source UDP/TCP ports from the range 2000-65535. +Due to the multi-threaded program structure there are slight discrepancies in +the timespan during which metrics are collected for any given thread. The +statistics printouts ignore this and are thus ever-so-slightly inaccurate. The +error margin decreases proportionally to the volume of data & timespan over +which they are collected. + Exit values ----------- diff --git a/doc/man_kzonecheck.rst b/doc/man_kzonecheck.rst index 3a10863..c0dae37 100644 --- a/doc/man_kzonecheck.rst +++ b/doc/man_kzonecheck.rst @@ -54,7 +54,8 @@ Options Print the program help. **-V**, **--version** - Print the program version. + Print the program version. The option **-VV** makes the program + print the compile time configuration summary. Exit values ----------- diff --git a/doc/man_kzonesign.rst b/doc/man_kzonesign.rst index c759c57..a1981ee 100644 --- a/doc/man_kzonesign.rst +++ b/doc/man_kzonesign.rst @@ -55,7 +55,8 @@ Options Print the program help. **-V**, **--version** - Print the program version. + Print the program version. The option **-VV** makes the program + print the compile time configuration summary. Exit values ----------- diff --git a/doc/migration.rst b/doc/migration.rst index f79539c..7c4a279 100644 --- a/doc/migration.rst +++ b/doc/migration.rst @@ -249,19 +249,19 @@ Configuration changes - Ignored obsolete options (with a notice log): - - ``server.max-journal-depth`` - - ``server.max-journal-usage`` - - ``server.max-refresh-interval`` - - ``server.min-refresh-interval`` - ``server.max-ipv4-udp-payload`` - ``server.max-ipv6-udp-payload`` - ``server.max-udp-payload`` - ``server.max-tcp-clients`` - ``server.tcp-reply-timeout`` + - ``zone.max-journal-depth`` + - ``zone.max-journal-usage`` + - ``zone.max-refresh-interval`` + - ``zone.min-refresh-interval`` + - ``zone.max-zone-size`` - ``template.journal-db`` - ``template.kasp-db`` - ``template.timer-db`` - - ``template.max-zone-size`` - ``template.max-journal-db-size`` - ``template.max-timer-db-size`` - ``template.max-kasp-db-size`` @@ -393,6 +393,86 @@ Query module API change The function ``knotd_qdata_local_addr()`` only takes one parameter. +.. _Upgrade 3.3.x to 3.4.x: + +Upgrade 3.3.x to 3.4.x +====================== + +There are the following changes between Knot DNS versions 3.4.x and 3.3.x. + +DNSSEC +------ + +- DNSSEC validation fails if the remaining RRSIG validity is shorter than + the corresponding :ref:`policy_rrsig-refresh` value. +- SKR verification fails if the end of a DNSKEY RRSIG validity period doesn't + cover the next DNSKEY snapshot. +- If DNSSEC signing is enabled, the outbound request's EDNS expire value is + lowered to the earliest RRSIG expiration if it is higher. + +Semantic checks +--------------- + +- Just one SOA record is required. +- Unified DNAME and CNAME semantic checks (see :ref:`Handling CNAME and DNAME-related updates`). + +Configuration changes +--------------------- + +- The server no longer allows concurrent control zone and configuration transactions. +- The server no longer allows opening a zone transaction when a blocking command is running. +- Removed already ignored obsolete options: + + - ``server.max-ipv4-udp-payload`` + - ``server.max-ipv6-udp-payload`` + - ``server.max-udp-payload`` + - ``server.max-tcp-clients`` + - ``server.tcp-handshake-timeout`` + - ``server.tcp-reply-timeout`` + - ``server.listen-xdp`` + - ``xdp.quic-log`` + - ``zone.max-journal-depth`` + - ``zone.max-journal-usage`` + - ``zone.max-refresh-interval`` + - ``zone.min-refresh-interval`` + - ``zone.max-zone-size`` + - ``zone.disable-any`` + - ``template.journal-db`` + - ``template.kasp-db`` + - ``template.timer-db`` + - ``template.max-journal-db-size`` + - ``template.max-timer-db-size`` + - ``template.max-kasp-db-size`` + - ``template.journal-db-mode`` + +Utilities +--------- + +- Changed defaults: + + - :doc:`kdig<man_kdig>`: enabled ``+edns`` and ``+bufsize=1232`` + +- Removed legacy parameters: + + - :doc:`keymgr<man_keymgr>`: ``--brief`` + - :doc:`kjournalprint<man_kjournalprint>`: ``--no-color`` + - :doc:`kjournalprint<man_kjournalprint>`: database specification without ``--dir`` + - :doc:`kjournalprint<man_kcatalogprint>`: database specification without ``--dir`` + +Documentation +------------- + +- Info pages are no longer supported. + +Building notes +-------------- + +- A GCC or LLVM Clang compiler with C11 support is required. +- Minimum required *GnuTLS* version is 3.6.10. +- *Libidn* version 1 is no longer supported. +- *Liburcu* must be available via pkg-config. +- Linux distributions CentOS 7, Debian 10, and Ubuntu 18.04 are no longer supported. + .. _Knot DNS for BIND users: Knot DNS for BIND users diff --git a/doc/operation.rst b/doc/operation.rst index 5754147..5c2bdf2 100644 --- a/doc/operation.rst +++ b/doc/operation.rst @@ -632,7 +632,7 @@ continues along the lines of :rfc:`6781#section-4.1.2`:: 2024-02-14T15:20:00+0100 info: [example.com.] DNSSEC, key, tag 36185, algorithm ECDSAP256SHA256, public, active 2024-02-14T15:20:00+0100 info: [example.com.] DNSSEC, key, tag 3375, algorithm ECDSAP256SHA256, KSK, public, active+ 2024-02-14T15:20:00+0100 info: [example.com.] DNSSEC, signing started - 2024-02-14T15:20:00+0100 info: [example.com.] DNSSEC, successfully signed, serial 2010111204 + 2024-02-14T15:20:00+0100 info: [example.com.] DNSSEC, successfully signed, serial 2010111204, new RRSIGs 3 2024-02-14T15:20:00+0100 info: [example.com.] DNSSEC, next signing at 2024-02-14T15:20:12+0100 ... (propagation-delay + dnskey-ttl) ... @@ -643,7 +643,7 @@ continues along the lines of :rfc:`6781#section-4.1.2`:: 2024-02-14T15:20:12+0100 info: [example.com.] DNSSEC, key, tag 36185, algorithm ECDSAP256SHA256, public, active 2024-02-14T15:20:12+0100 info: [example.com.] DNSSEC, key, tag 3375, algorithm ECDSAP256SHA256, KSK, public, ready, active+ 2024-02-14T15:20:12+0100 info: [example.com.] DNSSEC, signing started - 2024-02-14T15:20:12+0100 info: [example.com.] DNSSEC, successfully signed, serial 2010111205 + 2024-02-14T15:20:12+0100 info: [example.com.] DNSSEC, successfully signed, serial 2010111205, new RRSIGs 6 2024-02-14T15:20:12+0100 info: [example.com.] DNSSEC, next signing at 2024-02-28T15:19:37+0100 At this point the new KSK has to be submitted to the parent zone. Knot detects the updated parent's DS @@ -660,7 +660,7 @@ operator must confirm it manually (using ``knotc zone-ksk-submitted``):: 2024-02-14T15:20:16+0100 info: [example.com.] DNSSEC, key, tag 36185, algorithm ECDSAP256SHA256, public, active 2024-02-14T15:20:16+0100 info: [example.com.] DNSSEC, key, tag 3375, algorithm ECDSAP256SHA256, KSK, public, active 2024-02-14T15:20:16+0100 info: [example.com.] DNSSEC, signing started - 2024-02-14T15:20:16+0100 info: [example.com.] DNSSEC, successfully signed, serial 2010111206 + 2024-02-14T15:20:16+0100 info: [example.com.] DNSSEC, successfully signed, serial 2010111206, new RRSIGs 2 2024-02-14T15:20:16+0100 info: [example.com.] DNSSEC, next signing at 2024-02-14T15:20:23+0100 ... (parent's DS TTL is 7 seconds) ... @@ -670,7 +670,7 @@ operator must confirm it manually (using ``knotc zone-ksk-submitted``):: 2024-02-14T15:20:23+0100 info: [example.com.] DNSSEC, key, tag 36185, algorithm ECDSAP256SHA256, public, active 2024-02-14T15:20:23+0100 info: [example.com.] DNSSEC, key, tag 3375, algorithm ECDSAP256SHA256, KSK, public, active 2024-02-14T15:20:23+0100 info: [example.com.] DNSSEC, signing started - 2024-02-14T15:20:23+0100 info: [example.com.] DNSSEC, successfully signed, serial 2010111207 + 2024-02-14T15:20:23+0100 info: [example.com.] DNSSEC, successfully signed, serial 2010111207, new RRSIGs 2 2024-02-14T15:20:23+0100 info: [example.com.] DNSSEC, next signing at 2024-02-14T15:21:54+0100 Upon the zone's ZSK lifetime expiration, a new ZSK is generated and the rollover @@ -685,7 +685,7 @@ continues along the lines of :rfc:`6781#section-4.1.1`:: 2024-02-14T15:21:54+0100 info: [example.com.] DNSSEC, key, tag 3375, algorithm ECDSAP256SHA256, KSK, public, active 2024-02-14T15:21:54+0100 info: [example.com.] DNSSEC, key, tag 38559, algorithm ECDSAP256SHA256, public 2024-02-14T15:21:54+0100 info: [example.com.] DNSSEC, signing started - 2024-02-14T15:21:54+0100 info: [example.com.] DNSSEC, successfully signed, serial 2010111208 + 2024-02-14T15:21:54+0100 info: [example.com.] DNSSEC, successfully signed, serial 2010111208, new RRSIGs 2 2024-02-14T15:21:54+0100 info: [example.com.] DNSSEC, next signing at 2024-02-14T15:22:06+0100 ... (propagation-delay + dnskey-ttl) ... @@ -696,7 +696,7 @@ continues along the lines of :rfc:`6781#section-4.1.1`:: 2024-02-14T15:22:06+0100 info: [example.com.] DNSSEC, key, tag 3375, algorithm ECDSAP256SHA256, KSK, public, active 2024-02-14T15:22:06+0100 info: [example.com.] DNSSEC, key, tag 38559, algorithm ECDSAP256SHA256, public, active 2024-02-14T15:22:06+0100 info: [example.com.] DNSSEC, signing started - 2024-02-14T15:22:06+0100 info: [example.com.] DNSSEC, successfully signed, serial 2010111209 + 2024-02-14T15:22:06+0100 info: [example.com.] DNSSEC, successfully signed, serial 2010111209, new RRSIGs 14 2024-02-14T15:22:06+0100 info: [example.com.] DNSSEC, next signing at 2024-02-14T15:22:23+0100 ... (propagation-delay + zone-max-ttl) ... @@ -706,7 +706,7 @@ continues along the lines of :rfc:`6781#section-4.1.1`:: 2024-02-14T15:22:23+0100 info: [example.com.] DNSSEC, key, tag 3375, algorithm ECDSAP256SHA256, KSK, public, active 2024-02-14T15:22:23+0100 info: [example.com.] DNSSEC, key, tag 38559, algorithm ECDSAP256SHA256, public, active 2024-02-14T15:22:23+0100 info: [example.com.] DNSSEC, signing started - 2024-02-14T15:22:23+0100 info: [example.com.] DNSSEC, successfully signed, serial 2010111210 + 2024-02-14T15:22:23+0100 info: [example.com.] DNSSEC, successfully signed, serial 2010111210, new RRSIGs 2 2024-02-14T15:22:23+0100 info: [example.com.] DNSSEC, next signing at 2024-02-14T15:24:06+0100 Further rollovers:: @@ -722,7 +722,7 @@ Further rollovers:: 2024-02-14T15:24:06+0100 info: [example.com.] DNSSEC, key, tag 38559, algorithm ECDSAP256SHA256, public, active 2024-02-14T15:24:06+0100 info: [example.com.] DNSSEC, key, tag 59825, algorithm ECDSAP256SHA256, public 2024-02-14T15:24:06+0100 info: [example.com.] DNSSEC, signing started - 2024-02-14T15:24:06+0100 info: [example.com.] DNSSEC, successfully signed, serial 2010111211 + 2024-02-14T15:24:06+0100 info: [example.com.] DNSSEC, successfully signed, serial 2010111211, new RRSIGs 2 2024-02-14T15:24:06+0100 info: [example.com.] DNSSEC, next signing at 2024-02-14T15:24:18+0100 ... @@ -736,7 +736,7 @@ Further rollovers:: 2024-02-14T15:25:00+0100 info: [example.com.] DNSSEC, key, tag 59825, algorithm ECDSAP256SHA256, public, active 2024-02-14T15:25:00+0100 info: [example.com.] DNSSEC, key, tag 50822, algorithm ECDSAP256SHA256, KSK, public, active+ 2024-02-14T15:25:00+0100 info: [example.com.] DNSSEC, signing started - 2024-02-14T15:25:00+0100 info: [example.com.] DNSSEC, successfully signed, serial 2010111214 + 2024-02-14T15:25:00+0100 info: [example.com.] DNSSEC, successfully signed, serial 2010111214, new RRSIGs 3 2024-02-14T15:25:00+0100 info: [example.com.] DNSSEC, next signing at 2024-02-14T15:25:12+0100 ... @@ -1282,12 +1282,12 @@ if the backup was created for only a subset of zones. turns off some verification checks, it shouldn't be used in other cases. .. NOTE:: - For QUIC, only the auto-generated key is restored. The ``zone-restore`` - command doesn't restore a user-defined QUIC key and certificate so as to + For QUIC/TLS, only the auto-generated key is restored. The ``zone-restore`` + command doesn't restore a user-defined QUIC/TLS key and certificate so as to avoid possible configuration management conflicts and they must be restored from the backup (its subdirectory ``quic``) manually. In all cases, restart of the Knot server after the restore is necessary for the restored - QUIC key/certificate to take effect. + QUIC/TLS key/certificate to take effect. Limitations ----------- @@ -1375,9 +1375,15 @@ Pre-requisites * A multiqueue network card, which offers enough Combined RX/TX channels, with native XDP support is highly recommended. Successfully tested cards: + * NVIDIA (Mellanox) ConnectX-6 Dx (driver `mlx5_core`), maximum number of channels + per interface is 63. Official drivers are recommended. * Intel series 700 (driver `i40e`), maximum number of channels per interface is 64. - * Intel series 500 (driver `ixgbe`), maximum number of channels per interface is 64. - The number of CPUs available has to be at most 64! + Linux kernel drivers are recommended. + + Cards with known instability issues: + + * Intel series E810 (driver `ice`). + * Intel series 500 (driver `ixgbe`). * If the `knotd` service is not directly executed in the privileged mode, some additional Linux capabilities have to be set: diff --git a/doc/reference.rst b/doc/reference.rst index 6cb42f3..1aefc57 100644 --- a/doc/reference.rst +++ b/doc/reference.rst @@ -20,9 +20,10 @@ the following symbols: - ``STR`` – Textual string - ``HEXSTR`` – Hexadecimal string (with ``0x`` prefix) - ``BOOL`` – Boolean value (``on``/``off`` or ``true``/``false``) -- ``TIME`` – Number of seconds, an integer with possible time multiplier suffix - (``s`` ~ 1, ``m`` ~ 60, ``h`` ~ 3600 or ``d`` ~ 24 * 3600) -- ``SIZE`` – Number of bytes, an integer with possible size multiplier suffix +- ``TIME`` – Number of seconds, an integer with a possible time multiplier suffix + (``s`` ~ 1, ``m`` ~ 60, ``h`` ~ 3600, ``d`` ~ 24 * 3600, ``w`` ~ 7 * 24 * 3600, + ``M`` ~ 30 * 24 * 3600, ``y`` ~ 365 * 24 * 3600) +- ``SIZE`` – Number of bytes, an integer with a possible size multiplier suffix (``B`` ~ 1, ``K`` ~ 1024, ``M`` ~ 1024^2 or ``G`` ~ 1024^3) - ``BASE64`` – Base64 encoded string - ``ADDR`` – IPv4 or IPv6 address @@ -217,6 +218,7 @@ General options related to the server. dbus-init-delay: TIME listen: ADDR[@INT] | STR ... listen-quic: ADDR[@INT] ... + listen-tls: ADDR[@INT] ... .. CAUTION:: When you change configuration parameters dynamically or via configuration file @@ -561,12 +563,10 @@ Maximum EDNS0 UDP payload size for IPv6. key-file -------- -Path to a server key PEM file which is used for DNS over QUIC communication. +Path to a server key PEM file which is used for DNS over QUIC/TLS communication. A non-absolute path of a user specified key file is relative to the :file:`@config_dir@` directory. -Change of this parameter requires restart of the Knot server to take effect. - *Default:* auto-generated key .. _server_cert-file: @@ -574,11 +574,9 @@ Change of this parameter requires restart of the Knot server to take effect. cert-file --------- -Path to a server certificate PEM file which is used for DNS over QUIC communication. +Path to a server certificate PEM file which is used for DNS over QUIC/TLS communication. A non-absolute path is relative to the :file:`@config_dir@` directory. -Change of this parameter requires restart of the Knot server to take effect. - *Default:* one-time in-memory certificate .. _server_edns-client-subnet: @@ -646,16 +644,17 @@ Possible values: - ``stopped`` when the server shutdown sequence is initiated. - ``zone-updated`` – The signal ``zone_updated`` is emitted when a zone has been updated; the signal parameters are `zone name` and `zone SOA serial`. -- ``keys-updated`` - The signal ``keys_updated`` is emitted when a DNSSEC key set - of this zone is updated. +- ``keys-updated`` - The signal ``keys_updated`` is emitted when a DNSSEC key set + is updated; the signal parameter is `zone name`. - ``ksk-submission`` – The signal ``zone_ksk_submission`` is emitted if there is a ready KSK present when the zone is signed; the signal parameters are `zone name`, `KSK keytag`, and `KSK KASP id`. - ``dnssec-invalid`` – The signal ``zone_dnssec_invalid`` is emitted when DNSSEC - validation fails; the signal parameter is `zone name`. + validation fails; the signal parameters are `zone name`, and `remaining seconds` + until an RRSIG expires. .. NOTE:: - This function requires systemd version at least 221. + This function requires systemd version at least 221 or libdbus. Change of this parameter requires restart of the Knot server to take effect. @@ -704,9 +703,17 @@ Change of this parameter requires restart of the Knot server to take effect. *Default:* not set -.. NOTE:: - Incoming :ref:`DDNS<dynamic updates>` over QUIC isn't supported. - The server always responds with SERVFAIL. +.. _server_listen-tls: + +listen-tls +---------- + +One or more IP addresses (and optionally ports) where the server listens +for incoming queries over TLS protocol (DoT). + +Change of this parameter requires restart of the Knot server to take effect. + +*Default:* not set .. _xdp section: @@ -730,6 +737,9 @@ Various options related to XDP listening, especially TCP. tcp-idle-reset-timeout: TIME tcp-resend-timeout: TIME route-check: BOOL + ring-size: INT + busypoll-budget: INT + busypoll-timeout: INT .. CAUTION:: When you change configuration parameters dynamically or via configuration file @@ -912,6 +922,57 @@ Change of this parameter requires restart of the Knot server to take effect. *Default:* ``off`` +.. _xdp_ring-size: + +ring-size +--------- + +Size of RX, FQ, TX, and CQ rings. + +Change of this parameter requires restart of the Knot server to take effect. + +.. NOTE:: + This value should be at least as high as the configured RX size of the + network device in the XDP mode. + +*Default:* ``2048`` + +.. _xdp_busypoll-budget: + +busypoll-budget +--------------- + +If set to a positive value, preferred busy polling is enabled with the +specified budget. + +Change of this parameter requires restart of the Knot server to take effect. + +.. NOTE:: + + Preferred busy polling also requires setting ``napi_defer_hard_irqs`` and + ``gro_flush_timeout`` for the appropriate network interface. E.g.:: + + echo 2 | sudo tee /sys/class/net/<interface>/napi_defer_hard_irqs + echo 200000 | sudo tee /sys/class/net/<interface>/gro_flush_timeout + +.. NOTE:: + + A recommended value is between 8 and 64. + +*Default:* ``0`` (disabled) + +.. _xdp_busypoll-timeout: + +busypoll-timeout +---------------- + +Timeout in microseconds of preferrred busy polling if enabled by +:ref:`xdp_busypoll-budget`. + +Change of this parameter requires restart of the Knot server to take effect. + +*Default:* ``20`` (20 microseconds) + .. _control section: ``control`` section @@ -1378,6 +1439,7 @@ transfer, target for a notification, etc.). address: ADDR[@INT] | STR ... via: ADDR[@INT] ... quic: BOOL + tls: BOOL key: key_id cert-key: BASE64 ... block-notify-after-transfer: BOOL @@ -1459,6 +1521,16 @@ with this remote. *Default:* ``off`` +.. _remote_tls: + +tls +--- + +If this option is set, the TLS (DoT) protocol will be used for outgoing communication +with this remote. + +*Default:* ``off`` + .. _remote_key: key @@ -1955,8 +2027,6 @@ Possible values: - ``ed448`` .. NOTE:: - Ed25519 algorithm is only available if compiled with GnuTLS 3.6.0+. - Ed448 algorithm is only available if compiled with GnuTLS 3.6.12+ and Nettle 3.6+. *Default:* ``ecdsap256sha256`` @@ -2134,6 +2204,10 @@ resolvers' caches. *Default:* 0.1 * :ref:`policy_rrsig-lifetime` + :ref:`policy_propagation-delay` + :ref:`policy_zone-max-ttl` +If :ref:`zone_dnssec-validation` is enabled: + +*Default:* ``1d`` (1 day) + .. _policy_rrsig-pre-refresh: rrsig-pre-refresh @@ -2847,7 +2921,9 @@ List of DNSSEC checks: The validation is not affected by :ref:`zone_dnssec-policy` configuration, except for :ref:`policy_signing-threads` option, which specifies the number -of threads for parallel validation. +of threads for parallel validation, and :ref:`policy_rrsig-refresh`, which +defines minimal allowed remaining RRSIG validity (otherwise a warning is +logged). .. NOTE:: diff --git a/doc/requirements.rst b/doc/requirements.rst index 584afa2..6b25fc1 100644 --- a/doc/requirements.rst +++ b/doc/requirements.rst @@ -60,9 +60,9 @@ Required libraries Knot DNS requires a few libraries to be available: +* gnutls >= 3.6.10 * libedit -* gnutls >= 3.3 -* liburcu >= 0.5.4 +* liburcu * lmdb >= 0.9.15 .. NOTE:: @@ -72,9 +72,9 @@ Knot DNS requires a few libraries to be available: Optional libraries ================== -International Domain Names support (IDNA2008 or IDNA2003) in :doc:`kdig<man_kdig>`: +International Domain Names support (IDNA2008) in :doc:`kdig<man_kdig>`: -* libidn2 (or libidn) +* libidn2 Systemd's startup notification mechanism and journald logging: diff --git a/python/Makefile.in b/python/Makefile.in index 817d7f7..4e254e1 100644 --- a/python/Makefile.in +++ b/python/Makefile.in @@ -317,6 +317,8 @@ infodir = @infodir@ install_sh = @install_sh@ libbpf_CFLAGS = @libbpf_CFLAGS@ libbpf_LIBS = @libbpf_LIBS@ +libdbus_CFLAGS = @libdbus_CFLAGS@ +libdbus_LIBS = @libdbus_LIBS@ libdir = @libdir@ libdnssec_SONAME = @libdnssec_SONAME@ libdnssec_SOVERSION = @libdnssec_SOVERSION@ @@ -328,8 +330,6 @@ libfstrm_CFLAGS = @libfstrm_CFLAGS@ libfstrm_LIBS = @libfstrm_LIBS@ libidn2_CFLAGS = @libidn2_CFLAGS@ libidn2_LIBS = @libidn2_LIBS@ -libidn_CFLAGS = @libidn_CFLAGS@ -libidn_LIBS = @libidn_LIBS@ libknot_SONAME = @libknot_SONAME@ libknot_SOVERSION = @libknot_SOVERSION@ libknot_VERSION_INFO = @libknot_VERSION_INFO@ @@ -347,7 +347,6 @@ libprotobuf_c_CFLAGS = @libprotobuf_c_CFLAGS@ libprotobuf_c_LIBS = @libprotobuf_c_LIBS@ liburcu_CFLAGS = @liburcu_CFLAGS@ liburcu_LIBS = @liburcu_LIBS@ -liburcu_PKGCONFIG = @liburcu_PKGCONFIG@ libxdp_CFLAGS = @libxdp_CFLAGS@ libxdp_LIBS = @libxdp_LIBS@ libzscanner_SONAME = @libzscanner_SONAME@ diff --git a/python/knot_exporter/Makefile.in b/python/knot_exporter/Makefile.in index dae875e..3f2824d 100644 --- a/python/knot_exporter/Makefile.in +++ b/python/knot_exporter/Makefile.in @@ -260,6 +260,8 @@ infodir = @infodir@ install_sh = @install_sh@ libbpf_CFLAGS = @libbpf_CFLAGS@ libbpf_LIBS = @libbpf_LIBS@ +libdbus_CFLAGS = @libdbus_CFLAGS@ +libdbus_LIBS = @libdbus_LIBS@ libdir = @libdir@ libdnssec_SONAME = @libdnssec_SONAME@ libdnssec_SOVERSION = @libdnssec_SOVERSION@ @@ -271,8 +273,6 @@ libfstrm_CFLAGS = @libfstrm_CFLAGS@ libfstrm_LIBS = @libfstrm_LIBS@ libidn2_CFLAGS = @libidn2_CFLAGS@ libidn2_LIBS = @libidn2_LIBS@ -libidn_CFLAGS = @libidn_CFLAGS@ -libidn_LIBS = @libidn_LIBS@ libknot_SONAME = @libknot_SONAME@ libknot_SOVERSION = @libknot_SOVERSION@ libknot_VERSION_INFO = @libknot_VERSION_INFO@ @@ -290,7 +290,6 @@ libprotobuf_c_CFLAGS = @libprotobuf_c_CFLAGS@ libprotobuf_c_LIBS = @libprotobuf_c_LIBS@ liburcu_CFLAGS = @liburcu_CFLAGS@ liburcu_LIBS = @liburcu_LIBS@ -liburcu_PKGCONFIG = @liburcu_PKGCONFIG@ libxdp_CFLAGS = @libxdp_CFLAGS@ libxdp_LIBS = @libxdp_LIBS@ libzscanner_SONAME = @libzscanner_SONAME@ diff --git a/python/libknot/Makefile.in b/python/libknot/Makefile.in index 06b1083..c93de6e 100644 --- a/python/libknot/Makefile.in +++ b/python/libknot/Makefile.in @@ -260,6 +260,8 @@ infodir = @infodir@ install_sh = @install_sh@ libbpf_CFLAGS = @libbpf_CFLAGS@ libbpf_LIBS = @libbpf_LIBS@ +libdbus_CFLAGS = @libdbus_CFLAGS@ +libdbus_LIBS = @libdbus_LIBS@ libdir = @libdir@ libdnssec_SONAME = @libdnssec_SONAME@ libdnssec_SOVERSION = @libdnssec_SOVERSION@ @@ -271,8 +273,6 @@ libfstrm_CFLAGS = @libfstrm_CFLAGS@ libfstrm_LIBS = @libfstrm_LIBS@ libidn2_CFLAGS = @libidn2_CFLAGS@ libidn2_LIBS = @libidn2_LIBS@ -libidn_CFLAGS = @libidn_CFLAGS@ -libidn_LIBS = @libidn_LIBS@ libknot_SONAME = @libknot_SONAME@ libknot_SOVERSION = @libknot_SOVERSION@ libknot_VERSION_INFO = @libknot_VERSION_INFO@ @@ -290,7 +290,6 @@ libprotobuf_c_CFLAGS = @libprotobuf_c_CFLAGS@ libprotobuf_c_LIBS = @libprotobuf_c_LIBS@ liburcu_CFLAGS = @liburcu_CFLAGS@ liburcu_LIBS = @liburcu_LIBS@ -liburcu_PKGCONFIG = @liburcu_PKGCONFIG@ libxdp_CFLAGS = @libxdp_CFLAGS@ libxdp_LIBS = @libxdp_LIBS@ libzscanner_SONAME = @libzscanner_SONAME@ diff --git a/python/libknot/libknot/probe.py b/python/libknot/libknot/probe.py index e6f09db..37b2cdf 100644 --- a/python/libknot/libknot/probe.py +++ b/python/libknot/libknot/probe.py @@ -12,9 +12,9 @@ class KnotProbeDataProto(enum.IntEnum): UDP = 0 TCP = 1 - QUIC = 3 - TLS = 4 - HTTPS = 5 + QUIC = 2 + TLS = 3 + HTTPS = 4 class KnotProbeDataDNSHdr(ctypes.BigEndianStructure): @@ -132,8 +132,10 @@ class KnotProbeData(ctypes.Structure): string += COL("UDP", GRN) elif self.proto == KnotProbeDataProto.TCP: string += COL("TCP", RED) - else: + elif self.proto == KnotProbeDataProto.QUIC: string += COL("QUIC", ORG) + else: + string += COL("TLS", YELW) if self.tcp_rtt > 0: string += ", RTT %.2f ms" % (self.tcp_rtt / 1000) string += "\n ID %u, " % self.query_hdr.id diff --git a/samples/Makefile.in b/samples/Makefile.in index cd4bf4b..bb71eec 100644 --- a/samples/Makefile.in +++ b/samples/Makefile.in @@ -259,6 +259,8 @@ infodir = @infodir@ install_sh = @install_sh@ libbpf_CFLAGS = @libbpf_CFLAGS@ libbpf_LIBS = @libbpf_LIBS@ +libdbus_CFLAGS = @libdbus_CFLAGS@ +libdbus_LIBS = @libdbus_LIBS@ libdir = @libdir@ libdnssec_SONAME = @libdnssec_SONAME@ libdnssec_SOVERSION = @libdnssec_SOVERSION@ @@ -270,8 +272,6 @@ libfstrm_CFLAGS = @libfstrm_CFLAGS@ libfstrm_LIBS = @libfstrm_LIBS@ libidn2_CFLAGS = @libidn2_CFLAGS@ libidn2_LIBS = @libidn2_LIBS@ -libidn_CFLAGS = @libidn_CFLAGS@ -libidn_LIBS = @libidn_LIBS@ libknot_SONAME = @libknot_SONAME@ libknot_SOVERSION = @libknot_SOVERSION@ libknot_VERSION_INFO = @libknot_VERSION_INFO@ @@ -289,7 +289,6 @@ libprotobuf_c_CFLAGS = @libprotobuf_c_CFLAGS@ libprotobuf_c_LIBS = @libprotobuf_c_LIBS@ liburcu_CFLAGS = @liburcu_CFLAGS@ liburcu_LIBS = @liburcu_LIBS@ -liburcu_PKGCONFIG = @liburcu_PKGCONFIG@ libxdp_CFLAGS = @libxdp_CFLAGS@ libxdp_LIBS = @libxdp_LIBS@ libzscanner_SONAME = @libzscanner_SONAME@ diff --git a/src/Makefile.in b/src/Makefile.in index 09daaa2..8630517 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -160,28 +160,29 @@ host_triplet = @host@ @STATIC_MODULE_queryacl_TRUE@am__append_41 = $(knot_modules_queryacl_la_SOURCES) @SHARED_MODULE_queryacl_TRUE@am__append_42 = knot/modules/queryacl.la @STATIC_MODULE_rrl_TRUE@am__append_43 = $(knot_modules_rrl_la_SOURCES) -@SHARED_MODULE_rrl_TRUE@am__append_44 = knot/modules/rrl.la -@STATIC_MODULE_stats_TRUE@am__append_45 = $(knot_modules_stats_la_SOURCES) -@SHARED_MODULE_stats_TRUE@am__append_46 = knot/modules/stats.la -@STATIC_MODULE_synthrecord_TRUE@am__append_47 = $(knot_modules_synthrecord_la_SOURCES) -@SHARED_MODULE_synthrecord_TRUE@am__append_48 = knot/modules/synthrecord.la -@STATIC_MODULE_whoami_TRUE@am__append_49 = $(knot_modules_whoami_la_SOURCES) -@SHARED_MODULE_whoami_TRUE@am__append_50 = knot/modules/whoami.la +@STATIC_MODULE_rrl_TRUE@am__append_44 = $(math_LIBS) +@SHARED_MODULE_rrl_TRUE@am__append_45 = knot/modules/rrl.la +@STATIC_MODULE_stats_TRUE@am__append_46 = $(knot_modules_stats_la_SOURCES) +@SHARED_MODULE_stats_TRUE@am__append_47 = knot/modules/stats.la +@STATIC_MODULE_synthrecord_TRUE@am__append_48 = $(knot_modules_synthrecord_la_SOURCES) +@SHARED_MODULE_synthrecord_TRUE@am__append_49 = knot/modules/synthrecord.la +@STATIC_MODULE_whoami_TRUE@am__append_50 = $(knot_modules_whoami_la_SOURCES) +@SHARED_MODULE_whoami_TRUE@am__append_51 = knot/modules/whoami.la bin_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) sbin_PROGRAMS = $(am__EXEEXT_3) $(am__EXEEXT_4) $(am__EXEEXT_5) -@HAVE_LIBUTILS_TRUE@am__append_51 = libknotus.la -@EMBEDDED_LIBNGTCP2_TRUE@@HAVE_LIBUTILS_TRUE@am__append_52 = $(libembngtcp2_LIBS) -@HAVE_UTILS_TRUE@am__append_53 = kdig khost knsec3hash knsupdate -@HAVE_DNSTAP_TRUE@@HAVE_UTILS_TRUE@am__append_54 = $(DNSTAP_CFLAGS) -@HAVE_DNSTAP_TRUE@@HAVE_UTILS_TRUE@am__append_55 = $(libdnstap_LIBS) -@HAVE_DNSTAP_TRUE@@HAVE_UTILS_TRUE@am__append_56 = $(DNSTAP_CFLAGS) -@HAVE_DNSTAP_TRUE@@HAVE_UTILS_TRUE@am__append_57 = $(libdnstap_LIBS) -@ENABLE_XDP_TRUE@@HAVE_UTILS_TRUE@am__append_58 = kxdpgun -@ENABLE_QUIC_TRUE@@ENABLE_XDP_TRUE@@HAVE_UTILS_TRUE@am__append_59 = $(gnutls_CFLAGS) -@ENABLE_QUIC_TRUE@@ENABLE_XDP_TRUE@@HAVE_UTILS_TRUE@am__append_60 = $(gnutls_LIBS) -@HAVE_DAEMON_TRUE@am__append_61 = knotc knotd -@HAVE_DAEMON_TRUE@@HAVE_UTILS_TRUE@am__append_62 = kzonecheck kzonesign -@HAVE_DAEMON_TRUE@@HAVE_UTILS_TRUE@am__append_63 = keymgr kjournalprint kcatalogprint +@HAVE_LIBUTILS_TRUE@am__append_52 = libknotus.la +@EMBEDDED_LIBNGTCP2_TRUE@@HAVE_LIBUTILS_TRUE@am__append_53 = $(libembngtcp2_LIBS) +@HAVE_UTILS_TRUE@am__append_54 = kdig khost knsec3hash knsupdate +@HAVE_DNSTAP_TRUE@@HAVE_UTILS_TRUE@am__append_55 = $(DNSTAP_CFLAGS) +@HAVE_DNSTAP_TRUE@@HAVE_UTILS_TRUE@am__append_56 = $(libdnstap_LIBS) +@HAVE_DNSTAP_TRUE@@HAVE_UTILS_TRUE@am__append_57 = $(DNSTAP_CFLAGS) +@HAVE_DNSTAP_TRUE@@HAVE_UTILS_TRUE@am__append_58 = $(libdnstap_LIBS) +@ENABLE_XDP_TRUE@@HAVE_UTILS_TRUE@am__append_59 = kxdpgun +@ENABLE_QUIC_TRUE@@ENABLE_XDP_TRUE@@HAVE_UTILS_TRUE@am__append_60 = $(gnutls_CFLAGS) +@ENABLE_QUIC_TRUE@@ENABLE_XDP_TRUE@@HAVE_UTILS_TRUE@am__append_61 = $(gnutls_LIBS) +@HAVE_DAEMON_TRUE@am__append_62 = knotc knotd +@HAVE_DAEMON_TRUE@@HAVE_UTILS_TRUE@am__append_63 = kzonecheck kzonesign +@HAVE_DAEMON_TRUE@@HAVE_UTILS_TRUE@am__append_64 = keymgr kjournalprint kcatalogprint subdir = src SUBDIRS = ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 @@ -198,7 +199,8 @@ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(include_libdnssec_HEADERS) \ $(include_libknotd_HEADERS) $(include_libzscanner_HEADERS) \ - $(am__nobase_include_libknot_HEADERS_DIST) $(am__DIST_COMMON) + $(am__nobase_include_libknot_HEADERS_DIST) $(noinst_HEADERS) \ + $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = config.h CONFIG_CLEAN_FILES = knotd.pc libknot.pc libdnssec.pc libzscanner.pc @@ -359,9 +361,12 @@ knot_modules_queryacl_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ @SHARED_MODULE_queryacl_TRUE@am_knot_modules_queryacl_la_rpath = \ @SHARED_MODULE_queryacl_TRUE@ -rpath $(pkglibdir) @SHARED_MODULE_rrl_TRUE@knot_modules_rrl_la_DEPENDENCIES = \ -@SHARED_MODULE_rrl_TRUE@ $(am__DEPENDENCIES_3) +@SHARED_MODULE_rrl_TRUE@ $(am__DEPENDENCIES_3) \ +@SHARED_MODULE_rrl_TRUE@ $(am__DEPENDENCIES_1) am_knot_modules_rrl_la_OBJECTS = knot/modules/rrl/la-rrl.lo \ - knot/modules/rrl/la-functions.lo + knot/modules/rrl/la-functions.lo \ + knot/modules/rrl/la-kru-generic.lo \ + knot/modules/rrl/la-kru-avx2.lo knot_modules_rrl_la_OBJECTS = $(am_knot_modules_rrl_la_OBJECTS) knot_modules_rrl_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ @@ -627,17 +632,19 @@ am__libknot_la_SOURCES_DIST = libknot/codes.c \ libknot/descriptor.c libknot/dname.c libknot/error.c \ libknot/db/db_lmdb.c libknot/db/db_trie.c libknot/packet/pkt.c \ libknot/packet/rrset-wire.c libknot/probe/data.c \ - libknot/probe/probe.c libknot/rdataset.c libknot/rrset-dump.c \ - libknot/rrset.c libknot/rrtype/naptr.c libknot/rrtype/opt.c \ - libknot/rrtype/tsig.c libknot/tsig-op.c libknot/tsig.c \ - libknot/yparser/yparser.c libknot/yparser/ypbody.c \ - libknot/yparser/ypformat.c libknot/yparser/ypschema.c \ - libknot/yparser/yptrafo.c libknot/xdp/tcp_iobuf.c \ - libknot/xdp/bpf-kernel-obj.c libknot/xdp/bpf-kernel-obj.h \ - libknot/xdp/bpf-user.c libknot/xdp/bpf-user.h \ - libknot/xdp/eth.c libknot/xdp/msg_init.h \ - libknot/xdp/protocols.h libknot/xdp/tcp.c libknot/xdp/xdp.c \ - libknot/quic/quic.c libknot/quic/quic_conn.c + libknot/probe/probe.c libknot/quic/tls.c \ + libknot/quic/tls_common.c libknot/rdataset.c \ + libknot/rrset-dump.c libknot/rrset.c libknot/rrtype/naptr.c \ + libknot/rrtype/opt.c libknot/rrtype/tsig.c libknot/tsig-op.c \ + libknot/tsig.c libknot/yparser/yparser.c \ + libknot/yparser/ypbody.c libknot/yparser/ypformat.c \ + libknot/yparser/ypschema.c libknot/yparser/yptrafo.c \ + libknot/xdp/tcp_iobuf.c libknot/xdp/bpf-kernel-obj.c \ + libknot/xdp/bpf-kernel-obj.h libknot/xdp/bpf-user.c \ + libknot/xdp/bpf-user.h libknot/xdp/eth.c \ + libknot/xdp/msg_init.h libknot/xdp/protocols.h \ + libknot/xdp/tcp.c libknot/xdp/xdp.c libknot/quic/quic.c \ + libknot/quic/quic_conn.c @ENABLE_XDP_TRUE@am__objects_1 = libknot/xdp/la-bpf-kernel-obj.lo \ @ENABLE_XDP_TRUE@ libknot/xdp/la-bpf-user.lo \ @ENABLE_XDP_TRUE@ libknot/xdp/la-eth.lo libknot/xdp/la-tcp.lo \ @@ -650,7 +657,8 @@ am_libknot_la_OBJECTS = libknot/la-codes.lo \ libknot/la-error.lo libknot/db/la-db_lmdb.lo \ libknot/db/la-db_trie.lo libknot/packet/la-pkt.lo \ libknot/packet/la-rrset-wire.lo libknot/probe/la-data.lo \ - libknot/probe/la-probe.lo libknot/la-rdataset.lo \ + libknot/probe/la-probe.lo libknot/quic/la-tls.lo \ + libknot/quic/la-tls_common.lo libknot/la-rdataset.lo \ libknot/la-rrset-dump.lo libknot/la-rrset.lo \ libknot/rrtype/la-naptr.lo libknot/rrtype/la-opt.lo \ libknot/rrtype/la-tsig.lo libknot/la-tsig-op.lo \ @@ -665,10 +673,11 @@ libknot_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ @STATIC_MODULE_dnstap_TRUE@am__DEPENDENCIES_10 = \ @STATIC_MODULE_dnstap_TRUE@ $(am__DEPENDENCIES_4) @STATIC_MODULE_geoip_TRUE@am__DEPENDENCIES_11 = $(am__DEPENDENCIES_1) +@STATIC_MODULE_rrl_TRUE@am__DEPENDENCIES_12 = $(am__DEPENDENCIES_1) libknotd_la_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_7) $(am__DEPENDENCIES_10) \ - $(am__DEPENDENCIES_11) + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_7) \ + $(am__DEPENDENCIES_10) $(am__DEPENDENCIES_11) \ + $(am__DEPENDENCIES_12) am__libknotd_la_SOURCES_DIST = knot/catalog/catalog_db.c \ knot/catalog/catalog_db.h knot/catalog/catalog_update.c \ knot/catalog/catalog_update.h knot/catalog/generate.c \ @@ -705,15 +714,15 @@ am__libknotd_la_SOURCES_DIST = knot/catalog/catalog_db.c \ knot/events/handlers/flush.c \ knot/events/handlers/freeze_thaw.c knot/events/handlers/load.c \ knot/events/handlers/notify.c knot/events/handlers/refresh.c \ - knot/events/handlers/update.c knot/events/replan.c \ - knot/events/replan.h knot/nameserver/axfr.c \ - knot/nameserver/axfr.h knot/nameserver/chaos.c \ - knot/nameserver/chaos.h knot/nameserver/internet.c \ - knot/nameserver/internet.h knot/nameserver/ixfr.c \ - knot/nameserver/ixfr.h knot/nameserver/log.h \ - knot/nameserver/notify.c knot/nameserver/notify.h \ - knot/nameserver/nsec_proofs.c knot/nameserver/nsec_proofs.h \ - knot/nameserver/process_query.c \ + knot/events/handlers/update.c knot/events/handlers/validate.c \ + knot/events/replan.c knot/events/replan.h \ + knot/nameserver/axfr.c knot/nameserver/axfr.h \ + knot/nameserver/chaos.c knot/nameserver/chaos.h \ + knot/nameserver/internet.c knot/nameserver/internet.h \ + knot/nameserver/ixfr.c knot/nameserver/ixfr.h \ + knot/nameserver/log.h knot/nameserver/notify.c \ + knot/nameserver/notify.h knot/nameserver/nsec_proofs.c \ + knot/nameserver/nsec_proofs.h knot/nameserver/process_query.c \ knot/nameserver/process_query.h knot/nameserver/query_module.c \ knot/nameserver/query_module.h knot/nameserver/tsig_ctx.c \ knot/nameserver/tsig_ctx.h knot/nameserver/update.c \ @@ -721,14 +730,15 @@ am__libknotd_la_SOURCES_DIST = knot/catalog/catalog_db.c \ knot/nameserver/xfr.h knot/query/capture.c \ knot/query/capture.h knot/query/layer.h knot/query/query.c \ knot/query/query.h knot/query/requestor.c \ - knot/query/requestor.h knot/common/evsched.c \ - knot/common/evsched.h knot/common/fdset.c knot/common/fdset.h \ - knot/common/log.c knot/common/log.h knot/common/process.c \ - knot/common/process.h knot/common/stats.c knot/common/stats.h \ - knot/common/systemd.c knot/common/systemd.h \ - knot/common/unreachable.c knot/common/unreachable.h \ - knot/journal/journal_basic.c knot/journal/journal_basic.h \ - knot/journal/journal_metadata.c \ + knot/query/requestor.h knot/query/tls-requestor.c \ + knot/query/tls-requestor.h knot/common/dbus.c \ + knot/common/dbus.h knot/common/evsched.c knot/common/evsched.h \ + knot/common/fdset.c knot/common/fdset.h knot/common/log.c \ + knot/common/log.h knot/common/process.c knot/common/process.h \ + knot/common/stats.c knot/common/stats.h knot/common/systemd.c \ + knot/common/systemd.h knot/common/unreachable.c \ + knot/common/unreachable.h knot/journal/journal_basic.c \ + knot/journal/journal_basic.h knot/journal/journal_metadata.c \ knot/journal/journal_metadata.h knot/journal/journal_read.c \ knot/journal/journal_read.h knot/journal/journal_write.c \ knot/journal/journal_write.h knot/journal/knot_lmdb.c \ @@ -774,7 +784,8 @@ am__libknotd_la_SOURCES_DIST = knot/catalog/catalog_db.c \ knot/modules/onlinesign/nsec_next.h knot/modules/probe/probe.c \ knot/modules/queryacl/queryacl.c knot/modules/rrl/rrl.c \ knot/modules/rrl/functions.c knot/modules/rrl/functions.h \ - knot/modules/stats/stats.c \ + knot/modules/rrl/kru-generic.c knot/modules/rrl/kru-avx2.c \ + knot/modules/rrl/kru.h knot/modules/stats/stats.c \ knot/modules/synthrecord/synthrecord.c \ knot/modules/whoami/whoami.c @ENABLE_QUIC_TRUE@am__objects_3 = \ @@ -801,7 +812,9 @@ am__objects_18 = knot/modules/probe/libknotd_la-probe.lo am__objects_20 = knot/modules/queryacl/libknotd_la-queryacl.lo @STATIC_MODULE_queryacl_TRUE@am__objects_21 = $(am__objects_20) am__objects_22 = knot/modules/rrl/libknotd_la-rrl.lo \ - knot/modules/rrl/libknotd_la-functions.lo + knot/modules/rrl/libknotd_la-functions.lo \ + knot/modules/rrl/libknotd_la-kru-generic.lo \ + knot/modules/rrl/libknotd_la-kru-avx2.lo @STATIC_MODULE_rrl_TRUE@am__objects_23 = $(am__objects_22) am__objects_24 = knot/modules/stats/libknotd_la-stats.lo @STATIC_MODULE_stats_TRUE@am__objects_25 = $(am__objects_24) @@ -850,6 +863,7 @@ am_libknotd_la_OBJECTS = knot/catalog/libknotd_la-catalog_db.lo \ knot/events/handlers/libknotd_la-notify.lo \ knot/events/handlers/libknotd_la-refresh.lo \ knot/events/handlers/libknotd_la-update.lo \ + knot/events/handlers/libknotd_la-validate.lo \ knot/events/libknotd_la-replan.lo \ knot/nameserver/libknotd_la-axfr.lo \ knot/nameserver/libknotd_la-chaos.lo \ @@ -865,6 +879,8 @@ am_libknotd_la_OBJECTS = knot/catalog/libknotd_la-catalog_db.lo \ knot/query/libknotd_la-capture.lo \ knot/query/libknotd_la-query.lo \ knot/query/libknotd_la-requestor.lo \ + knot/query/libknotd_la-tls-requestor.lo \ + knot/common/libknotd_la-dbus.lo \ knot/common/libknotd_la-evsched.lo \ knot/common/libknotd_la-fdset.lo \ knot/common/libknotd_la-log.lo \ @@ -921,12 +937,11 @@ libknotd_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(libknotd_la_LDFLAGS) $(LDFLAGS) -o $@ @HAVE_DAEMON_TRUE@am_libknotd_la_rpath = -@EMBEDDED_LIBNGTCP2_TRUE@@HAVE_LIBUTILS_TRUE@am__DEPENDENCIES_12 = $(am__DEPENDENCIES_6) +@EMBEDDED_LIBNGTCP2_TRUE@@HAVE_LIBUTILS_TRUE@am__DEPENDENCIES_13 = $(am__DEPENDENCIES_6) @HAVE_LIBUTILS_TRUE@libknotus_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \ @HAVE_LIBUTILS_TRUE@ $(am__DEPENDENCIES_1) \ @HAVE_LIBUTILS_TRUE@ $(am__DEPENDENCIES_1) \ -@HAVE_LIBUTILS_TRUE@ $(am__DEPENDENCIES_1) \ -@HAVE_LIBUTILS_TRUE@ $(am__DEPENDENCIES_12) +@HAVE_LIBUTILS_TRUE@ $(am__DEPENDENCIES_13) am__libknotus_la_SOURCES_DIST = utils/common/exec.c \ utils/common/exec.h utils/common/hex.c utils/common/hex.h \ utils/common/https.c utils/common/https.h \ @@ -972,17 +987,17 @@ libzscanner_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ am__kcatalogprint_SOURCES_DIST = utils/kcatalogprint/main.c @HAVE_DAEMON_TRUE@@HAVE_UTILS_TRUE@am_kcatalogprint_OBJECTS = utils/kcatalogprint/kcatalogprint-main.$(OBJEXT) kcatalogprint_OBJECTS = $(am_kcatalogprint_OBJECTS) -am__DEPENDENCIES_13 = libknotd.la libknot.la libdnssec.la \ +am__DEPENDENCIES_14 = libknotd.la libknot.la libdnssec.la \ libzscanner.la $(am__DEPENDENCIES_3) $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) -@HAVE_LIBUTILS_TRUE@am__DEPENDENCIES_14 = libknotus.la libknot.la \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) +@HAVE_LIBUTILS_TRUE@am__DEPENDENCIES_15 = libknotus.la libknot.la \ @HAVE_LIBUTILS_TRUE@ libdnssec.la $(am__DEPENDENCIES_3) \ @HAVE_LIBUTILS_TRUE@ $(am__DEPENDENCIES_1) \ @HAVE_LIBUTILS_TRUE@ $(am__DEPENDENCIES_1) @HAVE_DAEMON_TRUE@@HAVE_UTILS_TRUE@kcatalogprint_DEPENDENCIES = \ -@HAVE_DAEMON_TRUE@@HAVE_UTILS_TRUE@ $(am__DEPENDENCIES_13) \ -@HAVE_DAEMON_TRUE@@HAVE_UTILS_TRUE@ $(am__DEPENDENCIES_14) +@HAVE_DAEMON_TRUE@@HAVE_UTILS_TRUE@ $(am__DEPENDENCIES_14) \ +@HAVE_DAEMON_TRUE@@HAVE_UTILS_TRUE@ $(am__DEPENDENCIES_15) kcatalogprint_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(kcatalogprint_LDFLAGS) $(LDFLAGS) -o $@ @@ -994,10 +1009,10 @@ am__kdig_SOURCES_DIST = utils/kdig/kdig_exec.c utils/kdig/kdig_exec.h \ @HAVE_UTILS_TRUE@ utils/kdig/kdig-kdig_main.$(OBJEXT) \ @HAVE_UTILS_TRUE@ utils/kdig/kdig-kdig_params.$(OBJEXT) kdig_OBJECTS = $(am_kdig_OBJECTS) -@HAVE_DNSTAP_TRUE@@HAVE_UTILS_TRUE@am__DEPENDENCIES_15 = \ +@HAVE_DNSTAP_TRUE@@HAVE_UTILS_TRUE@am__DEPENDENCIES_16 = \ @HAVE_DNSTAP_TRUE@@HAVE_UTILS_TRUE@ $(am__DEPENDENCIES_4) -@HAVE_UTILS_TRUE@kdig_DEPENDENCIES = $(am__DEPENDENCIES_14) \ -@HAVE_UTILS_TRUE@ $(am__DEPENDENCIES_15) +@HAVE_UTILS_TRUE@kdig_DEPENDENCIES = $(am__DEPENDENCIES_15) \ +@HAVE_UTILS_TRUE@ $(am__DEPENDENCIES_16) am__keymgr_SOURCES_DIST = utils/keymgr/bind_privkey.c \ utils/keymgr/bind_privkey.h utils/keymgr/functions.c \ utils/keymgr/functions.h utils/keymgr/keystore.c \ @@ -1010,8 +1025,8 @@ am__keymgr_SOURCES_DIST = utils/keymgr/bind_privkey.c \ @HAVE_DAEMON_TRUE@@HAVE_UTILS_TRUE@ utils/keymgr/keymgr-main.$(OBJEXT) keymgr_OBJECTS = $(am_keymgr_OBJECTS) @HAVE_DAEMON_TRUE@@HAVE_UTILS_TRUE@keymgr_DEPENDENCIES = \ -@HAVE_DAEMON_TRUE@@HAVE_UTILS_TRUE@ $(am__DEPENDENCIES_13) \ -@HAVE_DAEMON_TRUE@@HAVE_UTILS_TRUE@ $(am__DEPENDENCIES_14) +@HAVE_DAEMON_TRUE@@HAVE_UTILS_TRUE@ $(am__DEPENDENCIES_14) \ +@HAVE_DAEMON_TRUE@@HAVE_UTILS_TRUE@ $(am__DEPENDENCIES_15) keymgr_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(keymgr_LDFLAGS) $(LDFLAGS) -o $@ @@ -1025,14 +1040,14 @@ am__khost_SOURCES_DIST = utils/kdig/kdig_exec.c utils/kdig/kdig_exec.h \ @HAVE_UTILS_TRUE@ utils/khost/khost-khost_main.$(OBJEXT) \ @HAVE_UTILS_TRUE@ utils/khost/khost-khost_params.$(OBJEXT) khost_OBJECTS = $(am_khost_OBJECTS) -@HAVE_UTILS_TRUE@khost_DEPENDENCIES = $(am__DEPENDENCIES_14) \ -@HAVE_UTILS_TRUE@ $(am__DEPENDENCIES_15) +@HAVE_UTILS_TRUE@khost_DEPENDENCIES = $(am__DEPENDENCIES_15) \ +@HAVE_UTILS_TRUE@ $(am__DEPENDENCIES_16) am__kjournalprint_SOURCES_DIST = utils/kjournalprint/main.c @HAVE_DAEMON_TRUE@@HAVE_UTILS_TRUE@am_kjournalprint_OBJECTS = utils/kjournalprint/kjournalprint-main.$(OBJEXT) kjournalprint_OBJECTS = $(am_kjournalprint_OBJECTS) @HAVE_DAEMON_TRUE@@HAVE_UTILS_TRUE@kjournalprint_DEPENDENCIES = \ -@HAVE_DAEMON_TRUE@@HAVE_UTILS_TRUE@ $(am__DEPENDENCIES_13) \ -@HAVE_DAEMON_TRUE@@HAVE_UTILS_TRUE@ $(am__DEPENDENCIES_14) +@HAVE_DAEMON_TRUE@@HAVE_UTILS_TRUE@ $(am__DEPENDENCIES_14) \ +@HAVE_DAEMON_TRUE@@HAVE_UTILS_TRUE@ $(am__DEPENDENCIES_15) kjournalprint_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(kjournalprint_LDFLAGS) $(LDFLAGS) -o $@ @@ -1045,8 +1060,8 @@ am__knotc_SOURCES_DIST = utils/knotc/commands.c utils/knotc/commands.h \ @HAVE_DAEMON_TRUE@ utils/knotc/knotc-process.$(OBJEXT) \ @HAVE_DAEMON_TRUE@ utils/knotc/knotc-main.$(OBJEXT) knotc_OBJECTS = $(am_knotc_OBJECTS) -@HAVE_DAEMON_TRUE@knotc_DEPENDENCIES = $(am__DEPENDENCIES_13) \ -@HAVE_DAEMON_TRUE@ $(am__DEPENDENCIES_14) +@HAVE_DAEMON_TRUE@knotc_DEPENDENCIES = $(am__DEPENDENCIES_14) \ +@HAVE_DAEMON_TRUE@ $(am__DEPENDENCIES_15) knotc_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(knotc_LDFLAGS) $(LDFLAGS) -o $@ @@ -1054,7 +1069,7 @@ am__knotd_SOURCES_DIST = utils/knotd/main.c @HAVE_DAEMON_TRUE@am_knotd_OBJECTS = utils/knotd/knotd-main.$(OBJEXT) knotd_OBJECTS = $(am_knotd_OBJECTS) @HAVE_DAEMON_TRUE@knotd_DEPENDENCIES = $(am__DEPENDENCIES_1) \ -@HAVE_DAEMON_TRUE@ $(am__DEPENDENCIES_13) $(am__DEPENDENCIES_1) +@HAVE_DAEMON_TRUE@ $(am__DEPENDENCIES_14) $(am__DEPENDENCIES_1) knotd_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(knotd_LDFLAGS) $(LDFLAGS) -o $@ @@ -1075,28 +1090,31 @@ am__knsupdate_SOURCES_DIST = utils/knsupdate/knsupdate_exec.c \ @HAVE_UTILS_TRUE@ utils/knsupdate/knsupdate-knsupdate_main.$(OBJEXT) \ @HAVE_UTILS_TRUE@ utils/knsupdate/knsupdate-knsupdate_params.$(OBJEXT) knsupdate_OBJECTS = $(am_knsupdate_OBJECTS) -@HAVE_UTILS_TRUE@knsupdate_DEPENDENCIES = $(am__DEPENDENCIES_14) \ +@HAVE_UTILS_TRUE@knsupdate_DEPENDENCIES = $(am__DEPENDENCIES_15) \ @HAVE_UTILS_TRUE@ libzscanner.la am__kxdpgun_SOURCES_DIST = utils/kxdpgun/ip_route.c \ utils/kxdpgun/ip_route.h utils/kxdpgun/load_queries.c \ - utils/kxdpgun/load_queries.h utils/kxdpgun/main.c + utils/kxdpgun/load_queries.h utils/kxdpgun/main.c \ + utils/kxdpgun/main.h utils/kxdpgun/stats.c \ + utils/kxdpgun/stats.h @ENABLE_XDP_TRUE@@HAVE_UTILS_TRUE@am_kxdpgun_OBJECTS = utils/kxdpgun/kxdpgun-ip_route.$(OBJEXT) \ @ENABLE_XDP_TRUE@@HAVE_UTILS_TRUE@ utils/kxdpgun/kxdpgun-load_queries.$(OBJEXT) \ -@ENABLE_XDP_TRUE@@HAVE_UTILS_TRUE@ utils/kxdpgun/kxdpgun-main.$(OBJEXT) +@ENABLE_XDP_TRUE@@HAVE_UTILS_TRUE@ utils/kxdpgun/kxdpgun-main.$(OBJEXT) \ +@ENABLE_XDP_TRUE@@HAVE_UTILS_TRUE@ utils/kxdpgun/kxdpgun-stats.$(OBJEXT) kxdpgun_OBJECTS = $(am_kxdpgun_OBJECTS) -@ENABLE_QUIC_TRUE@@ENABLE_XDP_TRUE@@HAVE_UTILS_TRUE@am__DEPENDENCIES_16 = $(am__DEPENDENCIES_1) +@ENABLE_QUIC_TRUE@@ENABLE_XDP_TRUE@@HAVE_UTILS_TRUE@am__DEPENDENCIES_17 = $(am__DEPENDENCIES_1) @ENABLE_XDP_TRUE@@HAVE_UTILS_TRUE@kxdpgun_DEPENDENCIES = libknot.la \ @ENABLE_XDP_TRUE@@HAVE_UTILS_TRUE@ $(am__DEPENDENCIES_3) \ @ENABLE_XDP_TRUE@@HAVE_UTILS_TRUE@ $(am__DEPENDENCIES_1) \ @ENABLE_XDP_TRUE@@HAVE_UTILS_TRUE@ $(am__DEPENDENCIES_1) \ -@ENABLE_XDP_TRUE@@HAVE_UTILS_TRUE@ $(am__DEPENDENCIES_16) +@ENABLE_XDP_TRUE@@HAVE_UTILS_TRUE@ $(am__DEPENDENCIES_17) am__kzonecheck_SOURCES_DIST = utils/kzonecheck/main.c \ utils/kzonecheck/zone_check.c utils/kzonecheck/zone_check.h @HAVE_DAEMON_TRUE@@HAVE_UTILS_TRUE@am_kzonecheck_OBJECTS = utils/kzonecheck/kzonecheck-main.$(OBJEXT) \ @HAVE_DAEMON_TRUE@@HAVE_UTILS_TRUE@ utils/kzonecheck/kzonecheck-zone_check.$(OBJEXT) kzonecheck_OBJECTS = $(am_kzonecheck_OBJECTS) @HAVE_DAEMON_TRUE@@HAVE_UTILS_TRUE@kzonecheck_DEPENDENCIES = \ -@HAVE_DAEMON_TRUE@@HAVE_UTILS_TRUE@ $(am__DEPENDENCIES_13) +@HAVE_DAEMON_TRUE@@HAVE_UTILS_TRUE@ $(am__DEPENDENCIES_14) kzonecheck_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(kzonecheck_LDFLAGS) $(LDFLAGS) -o $@ @@ -1104,8 +1122,8 @@ am__kzonesign_SOURCES_DIST = utils/kzonesign/main.c @HAVE_DAEMON_TRUE@@HAVE_UTILS_TRUE@am_kzonesign_OBJECTS = utils/kzonesign/kzonesign-main.$(OBJEXT) kzonesign_OBJECTS = $(am_kzonesign_OBJECTS) @HAVE_DAEMON_TRUE@@HAVE_UTILS_TRUE@kzonesign_DEPENDENCIES = \ -@HAVE_DAEMON_TRUE@@HAVE_UTILS_TRUE@ $(am__DEPENDENCIES_13) \ -@HAVE_DAEMON_TRUE@@HAVE_UTILS_TRUE@ $(am__DEPENDENCIES_14) +@HAVE_DAEMON_TRUE@@HAVE_UTILS_TRUE@ $(am__DEPENDENCIES_14) \ +@HAVE_DAEMON_TRUE@@HAVE_UTILS_TRUE@ $(am__DEPENDENCIES_15) kzonesign_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(kzonesign_LDFLAGS) $(LDFLAGS) -o $@ @@ -1200,6 +1218,7 @@ am__depfiles_remade = contrib/$(DEPDIR)/libcontrib_la-base32hex.Plo \ knot/catalog/$(DEPDIR)/libknotd_la-catalog_update.Plo \ knot/catalog/$(DEPDIR)/libknotd_la-generate.Plo \ knot/catalog/$(DEPDIR)/libknotd_la-interpret.Plo \ + knot/common/$(DEPDIR)/libknotd_la-dbus.Plo \ knot/common/$(DEPDIR)/libknotd_la-evsched.Plo \ knot/common/$(DEPDIR)/libknotd_la-fdset.Plo \ knot/common/$(DEPDIR)/libknotd_la-log.Plo \ @@ -1247,6 +1266,7 @@ am__depfiles_remade = contrib/$(DEPDIR)/libcontrib_la-base32hex.Plo \ knot/events/handlers/$(DEPDIR)/libknotd_la-notify.Plo \ knot/events/handlers/$(DEPDIR)/libknotd_la-refresh.Plo \ knot/events/handlers/$(DEPDIR)/libknotd_la-update.Plo \ + knot/events/handlers/$(DEPDIR)/libknotd_la-validate.Plo \ knot/journal/$(DEPDIR)/libknotd_la-journal_basic.Plo \ knot/journal/$(DEPDIR)/libknotd_la-journal_metadata.Plo \ knot/journal/$(DEPDIR)/libknotd_la-journal_read.Plo \ @@ -1276,8 +1296,12 @@ am__depfiles_remade = contrib/$(DEPDIR)/libcontrib_la-base32hex.Plo \ knot/modules/queryacl/$(DEPDIR)/la-queryacl.Plo \ knot/modules/queryacl/$(DEPDIR)/libknotd_la-queryacl.Plo \ knot/modules/rrl/$(DEPDIR)/la-functions.Plo \ + knot/modules/rrl/$(DEPDIR)/la-kru-avx2.Plo \ + knot/modules/rrl/$(DEPDIR)/la-kru-generic.Plo \ knot/modules/rrl/$(DEPDIR)/la-rrl.Plo \ knot/modules/rrl/$(DEPDIR)/libknotd_la-functions.Plo \ + knot/modules/rrl/$(DEPDIR)/libknotd_la-kru-avx2.Plo \ + knot/modules/rrl/$(DEPDIR)/libknotd_la-kru-generic.Plo \ knot/modules/rrl/$(DEPDIR)/libknotd_la-rrl.Plo \ knot/modules/stats/$(DEPDIR)/la-stats.Plo \ knot/modules/stats/$(DEPDIR)/libknotd_la-stats.Plo \ @@ -1300,6 +1324,7 @@ am__depfiles_remade = contrib/$(DEPDIR)/libcontrib_la-base32hex.Plo \ knot/query/$(DEPDIR)/libknotd_la-query.Plo \ knot/query/$(DEPDIR)/libknotd_la-quic-requestor.Plo \ knot/query/$(DEPDIR)/libknotd_la-requestor.Plo \ + knot/query/$(DEPDIR)/libknotd_la-tls-requestor.Plo \ knot/server/$(DEPDIR)/libknotd_la-dthreads.Plo \ knot/server/$(DEPDIR)/libknotd_la-handler.Plo \ knot/server/$(DEPDIR)/libknotd_la-proxyv2.Plo \ @@ -1380,6 +1405,8 @@ am__depfiles_remade = contrib/$(DEPDIR)/libcontrib_la-base32hex.Plo \ libknot/probe/$(DEPDIR)/la-probe.Plo \ libknot/quic/$(DEPDIR)/la-quic.Plo \ libknot/quic/$(DEPDIR)/la-quic_conn.Plo \ + libknot/quic/$(DEPDIR)/la-tls.Plo \ + libknot/quic/$(DEPDIR)/la-tls_common.Plo \ libknot/rrtype/$(DEPDIR)/la-naptr.Plo \ libknot/rrtype/$(DEPDIR)/la-opt.Plo \ libknot/rrtype/$(DEPDIR)/la-tsig.Plo \ @@ -1438,6 +1465,7 @@ am__depfiles_remade = contrib/$(DEPDIR)/libcontrib_la-base32hex.Plo \ utils/kxdpgun/$(DEPDIR)/kxdpgun-ip_route.Po \ utils/kxdpgun/$(DEPDIR)/kxdpgun-load_queries.Po \ utils/kxdpgun/$(DEPDIR)/kxdpgun-main.Po \ + utils/kxdpgun/$(DEPDIR)/kxdpgun-stats.Po \ utils/kzonecheck/$(DEPDIR)/kzonecheck-main.Po \ utils/kzonecheck/$(DEPDIR)/kzonecheck-zone_check.Po \ utils/kzonesign/$(DEPDIR)/kzonesign-main.Po @@ -1528,7 +1556,8 @@ am__nobase_include_libknot_HEADERS_DIST = libknot/attribute.h \ libknot/db/db_trie.h libknot/packet/compr.h \ libknot/packet/pkt.h libknot/packet/rrset-wire.h \ libknot/packet/wire.h libknot/probe/data.h \ - libknot/probe/probe.h libknot/rdata.h libknot/rdataset.h \ + libknot/probe/probe.h libknot/quic/tls.h \ + libknot/quic/tls_common.h libknot/rdata.h libknot/rdataset.h \ libknot/rrset-dump.h libknot/rrset.h libknot/rrtype/dnskey.h \ libknot/rrtype/ds.h libknot/rrtype/naptr.h \ libknot/rrtype/nsec.h libknot/rrtype/nsec3.h \ @@ -1545,7 +1574,7 @@ am__nobase_include_libknot_HEADERS_DIST = libknot/attribute.h \ libknot/quic/quic_conn.h HEADERS = $(include_libdnssec_HEADERS) $(include_libknotd_HEADERS) \ $(include_libzscanner_HEADERS) \ - $(nobase_include_libknot_HEADERS) + $(nobase_include_libknot_HEADERS) $(noinst_HEADERS) RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ @@ -1751,6 +1780,8 @@ infodir = @infodir@ install_sh = @install_sh@ libbpf_CFLAGS = @libbpf_CFLAGS@ libbpf_LIBS = @libbpf_LIBS@ +libdbus_CFLAGS = @libdbus_CFLAGS@ +libdbus_LIBS = @libdbus_LIBS@ libdir = @libdir@ libdnssec_SONAME = @libdnssec_SONAME@ libdnssec_SOVERSION = @libdnssec_SOVERSION@ @@ -1762,8 +1793,6 @@ libfstrm_CFLAGS = @libfstrm_CFLAGS@ libfstrm_LIBS = @libfstrm_LIBS@ libidn2_CFLAGS = @libidn2_CFLAGS@ libidn2_LIBS = @libidn2_LIBS@ -libidn_CFLAGS = @libidn_CFLAGS@ -libidn_LIBS = @libidn_LIBS@ libknot_SONAME = @libknot_SONAME@ libknot_SOVERSION = @libknot_SOVERSION@ libknot_VERSION_INFO = @libknot_VERSION_INFO@ @@ -1781,7 +1810,6 @@ libprotobuf_c_CFLAGS = @libprotobuf_c_CFLAGS@ libprotobuf_c_LIBS = @libprotobuf_c_LIBS@ liburcu_CFLAGS = @liburcu_CFLAGS@ liburcu_LIBS = @liburcu_LIBS@ -liburcu_PKGCONFIG = @liburcu_PKGCONFIG@ libxdp_CFLAGS = @libxdp_CFLAGS@ libxdp_LIBS = @libxdp_LIBS@ libzscanner_SONAME = @libzscanner_SONAME@ @@ -1849,7 +1877,7 @@ CLEANFILES = $(am__append_5) libzscanner/scanner.c BUILT_SOURCES = $(am__append_4) libzscanner/scanner.c lib_LTLIBRARIES = libdnssec.la libknot.la libzscanner.la noinst_LTLIBRARIES = libcontrib.la $(am__append_3) $(am__append_6) \ - $(am__append_19) $(am__append_51) + $(am__append_19) $(am__append_52) pkgconfig_DATA = libdnssec.pc libknot.pc libzscanner.pc \ $(am__append_20) libcontrib_la_CPPFLAGS = $(AM_CPPFLAGS) $(CFLAG_VISIBILITY) \ @@ -1859,6 +1887,7 @@ libcontrib_la_LIBADD = $(pthread_LIBS) libcontrib_LIBS = libcontrib.la $(am__append_2) libcontrib_la_SOURCES = \ contrib/asan.h \ + contrib/atomic.h \ contrib/base32hex.c \ contrib/base32hex.h \ contrib/base64.c \ @@ -2121,25 +2150,26 @@ nobase_include_libknot_HEADERS = libknot/attribute.h libknot/codes.h \ libknot/db/db.h libknot/db/db_lmdb.h libknot/db/db_trie.h \ libknot/packet/compr.h libknot/packet/pkt.h \ libknot/packet/rrset-wire.h libknot/packet/wire.h \ - libknot/probe/data.h libknot/probe/probe.h libknot/rdata.h \ - libknot/rdataset.h libknot/rrset-dump.h libknot/rrset.h \ - libknot/rrtype/dnskey.h libknot/rrtype/ds.h \ - libknot/rrtype/naptr.h libknot/rrtype/nsec.h \ - libknot/rrtype/nsec3.h libknot/rrtype/nsec3param.h \ - libknot/rrtype/opt.h libknot/rrtype/rdname.h \ - libknot/rrtype/rrsig.h libknot/rrtype/soa.h \ - libknot/rrtype/svcb.h libknot/rrtype/tsig.h \ - libknot/rrtype/zonemd.h libknot/tsig-op.h libknot/tsig.h \ - libknot/wire.h libknot/yparser/yparser.h \ - libknot/yparser/ypformat.h libknot/yparser/ypschema.h \ - libknot/yparser/yptrafo.h libknot/version.h \ - libknot/xdp/tcp_iobuf.h libknot/xdp.h $(am__append_11) \ - $(am__append_15) + libknot/probe/data.h libknot/probe/probe.h libknot/quic/tls.h \ + libknot/quic/tls_common.h libknot/rdata.h libknot/rdataset.h \ + libknot/rrset-dump.h libknot/rrset.h libknot/rrtype/dnskey.h \ + libknot/rrtype/ds.h libknot/rrtype/naptr.h \ + libknot/rrtype/nsec.h libknot/rrtype/nsec3.h \ + libknot/rrtype/nsec3param.h libknot/rrtype/opt.h \ + libknot/rrtype/rdname.h libknot/rrtype/rrsig.h \ + libknot/rrtype/soa.h libknot/rrtype/svcb.h \ + libknot/rrtype/tsig.h libknot/rrtype/zonemd.h \ + libknot/tsig-op.h libknot/tsig.h libknot/wire.h \ + libknot/yparser/yparser.h libknot/yparser/ypformat.h \ + libknot/yparser/ypschema.h libknot/yparser/yptrafo.h \ + libknot/version.h libknot/xdp/tcp_iobuf.h libknot/xdp.h \ + $(am__append_11) $(am__append_15) libknot_la_SOURCES = libknot/codes.c libknot/control/control.c \ libknot/cookies.c libknot/descriptor.c libknot/dname.c \ libknot/error.c libknot/db/db_lmdb.c libknot/db/db_trie.c \ libknot/packet/pkt.c libknot/packet/rrset-wire.c \ - libknot/probe/data.c libknot/probe/probe.c libknot/rdataset.c \ + libknot/probe/data.c libknot/probe/probe.c libknot/quic/tls.c \ + libknot/quic/tls_common.c libknot/rdataset.c \ libknot/rrset-dump.c libknot/rrset.c libknot/rrtype/naptr.c \ libknot/rrtype/opt.c libknot/rrtype/tsig.c libknot/tsig-op.c \ libknot/tsig.c libknot/yparser/yparser.c \ @@ -2169,15 +2199,15 @@ nodist_libzscanner_la_SOURCES = \ libknotd_la_CPPFLAGS = $(AM_CPPFLAGS) $(CFLAG_VISIBILITY) \ $(libkqueue_CFLAGS) $(liburcu_CFLAGS) $(lmdb_CFLAGS) \ - $(systemd_CFLAGS) $(gnutls_CFLAGS) $(libngtcp2_CFLAGS) \ + $(systemd_CFLAGS) $(libdbus_CFLAGS) $(gnutls_CFLAGS) \ -DKNOTD_MOD_STATIC $(am__append_28) $(am__append_32) libknotd_la_LDFLAGS = $(AM_LDFLAGS) -export-symbols-regex '^knotd_' libknotd_la_LIBADD = $(dlopen_LIBS) $(libkqueue_LIBS) $(pthread_LIBS) \ - $(libngtcp2_LIBS) $(am__append_17) $(am__append_29) \ - $(am__append_33) + $(am__append_17) $(am__append_29) $(am__append_33) \ + $(am__append_44) libknotd_LIBS = libknotd.la libknot.la libdnssec.la libzscanner.la \ $(libcontrib_LIBS) $(liburcu_LIBS) $(lmdb_LIBS) \ - $(systemd_LIBS) $(gnutls_LIBS) + $(systemd_LIBS) $(libdbus_LIBS) $(gnutls_LIBS) include_libknotddir = $(includedir)/knot include_libknotd_HEADERS = \ @@ -2219,15 +2249,15 @@ libknotd_la_SOURCES = knot/catalog/catalog_db.c \ knot/events/handlers/flush.c \ knot/events/handlers/freeze_thaw.c knot/events/handlers/load.c \ knot/events/handlers/notify.c knot/events/handlers/refresh.c \ - knot/events/handlers/update.c knot/events/replan.c \ - knot/events/replan.h knot/nameserver/axfr.c \ - knot/nameserver/axfr.h knot/nameserver/chaos.c \ - knot/nameserver/chaos.h knot/nameserver/internet.c \ - knot/nameserver/internet.h knot/nameserver/ixfr.c \ - knot/nameserver/ixfr.h knot/nameserver/log.h \ - knot/nameserver/notify.c knot/nameserver/notify.h \ - knot/nameserver/nsec_proofs.c knot/nameserver/nsec_proofs.h \ - knot/nameserver/process_query.c \ + knot/events/handlers/update.c knot/events/handlers/validate.c \ + knot/events/replan.c knot/events/replan.h \ + knot/nameserver/axfr.c knot/nameserver/axfr.h \ + knot/nameserver/chaos.c knot/nameserver/chaos.h \ + knot/nameserver/internet.c knot/nameserver/internet.h \ + knot/nameserver/ixfr.c knot/nameserver/ixfr.h \ + knot/nameserver/log.h knot/nameserver/notify.c \ + knot/nameserver/notify.h knot/nameserver/nsec_proofs.c \ + knot/nameserver/nsec_proofs.h knot/nameserver/process_query.c \ knot/nameserver/process_query.h knot/nameserver/query_module.c \ knot/nameserver/query_module.h knot/nameserver/tsig_ctx.c \ knot/nameserver/tsig_ctx.h knot/nameserver/update.c \ @@ -2235,14 +2265,15 @@ libknotd_la_SOURCES = knot/catalog/catalog_db.c \ knot/nameserver/xfr.h knot/query/capture.c \ knot/query/capture.h knot/query/layer.h knot/query/query.c \ knot/query/query.h knot/query/requestor.c \ - knot/query/requestor.h knot/common/evsched.c \ - knot/common/evsched.h knot/common/fdset.c knot/common/fdset.h \ - knot/common/log.c knot/common/log.h knot/common/process.c \ - knot/common/process.h knot/common/stats.c knot/common/stats.h \ - knot/common/systemd.c knot/common/systemd.h \ - knot/common/unreachable.c knot/common/unreachable.h \ - knot/journal/journal_basic.c knot/journal/journal_basic.h \ - knot/journal/journal_metadata.c \ + knot/query/requestor.h knot/query/tls-requestor.c \ + knot/query/tls-requestor.h knot/common/dbus.c \ + knot/common/dbus.h knot/common/evsched.c knot/common/evsched.h \ + knot/common/fdset.c knot/common/fdset.h knot/common/log.c \ + knot/common/log.h knot/common/process.c knot/common/process.h \ + knot/common/stats.c knot/common/stats.h knot/common/systemd.c \ + knot/common/systemd.h knot/common/unreachable.c \ + knot/common/unreachable.h knot/journal/journal_basic.c \ + knot/journal/journal_basic.h knot/journal/journal_metadata.c \ knot/journal/journal_metadata.h knot/journal/journal_read.c \ knot/journal/journal_read.h knot/journal/journal_write.c \ knot/journal/journal_write.h knot/journal/knot_lmdb.c \ @@ -2279,15 +2310,15 @@ libknotd_la_SOURCES = knot/catalog/catalog_db.c \ $(am__append_21) $(am__append_23) $(am__append_25) \ $(am__append_27) $(am__append_31) $(am__append_35) \ $(am__append_37) $(am__append_39) $(am__append_41) \ - $(am__append_43) $(am__append_45) $(am__append_47) \ - $(am__append_49) + $(am__append_43) $(am__append_46) $(am__append_48) \ + $(am__append_50) KNOTD_MOD_CPPFLAGS = $(AM_CPPFLAGS) $(CFLAG_VISIBILITY) KNOTD_MOD_LDFLAGS = $(AM_LDFLAGS) -module -shared -avoid-version pkglib_LTLIBRARIES = $(am__append_22) $(am__append_24) \ $(am__append_26) $(am__append_30) $(am__append_34) \ $(am__append_36) $(am__append_38) $(am__append_40) \ - $(am__append_42) $(am__append_44) $(am__append_46) \ - $(am__append_48) $(am__append_50) + $(am__append_42) $(am__append_45) $(am__append_47) \ + $(am__append_49) $(am__append_51) knot_modules_authsignal_la_SOURCES = knot/modules/authsignal/authsignal.c @SHARED_MODULE_authsignal_TRUE@knot_modules_authsignal_la_LDFLAGS = $(KNOTD_MOD_LDFLAGS) @SHARED_MODULE_authsignal_TRUE@knot_modules_authsignal_la_CPPFLAGS = $(KNOTD_MOD_CPPFLAGS) @@ -2328,11 +2359,15 @@ knot_modules_queryacl_la_SOURCES = knot/modules/queryacl/queryacl.c @SHARED_MODULE_queryacl_TRUE@knot_modules_queryacl_la_CPPFLAGS = $(KNOTD_MOD_CPPFLAGS) knot_modules_rrl_la_SOURCES = knot/modules/rrl/rrl.c \ knot/modules/rrl/functions.c \ - knot/modules/rrl/functions.h + knot/modules/rrl/functions.h \ + knot/modules/rrl/kru-generic.c \ + knot/modules/rrl/kru-avx2.c \ + knot/modules/rrl/kru.h +noinst_HEADERS = knot/modules/rrl/kru.inc.c @SHARED_MODULE_rrl_TRUE@knot_modules_rrl_la_LDFLAGS = $(KNOTD_MOD_LDFLAGS) @SHARED_MODULE_rrl_TRUE@knot_modules_rrl_la_CPPFLAGS = $(KNOTD_MOD_CPPFLAGS) -@SHARED_MODULE_rrl_TRUE@knot_modules_rrl_la_LIBADD = $(libcontrib_LIBS) +@SHARED_MODULE_rrl_TRUE@knot_modules_rrl_la_LIBADD = $(libcontrib_LIBS) $(math_LIBS) knot_modules_stats_la_SOURCES = knot/modules/stats/stats.c @SHARED_MODULE_stats_TRUE@knot_modules_stats_la_LDFLAGS = $(KNOTD_MOD_LDFLAGS) @SHARED_MODULE_stats_TRUE@knot_modules_stats_la_CPPFLAGS = $(KNOTD_MOD_CPPFLAGS) @@ -2353,7 +2388,7 @@ knot_modules_whoami_la_SOURCES = knot/modules/whoami/whoami.c @HAVE_LIBUTILS_TRUE@libknotus_la_LDFLAGS = $(AM_LDFLAGS) $(LDFLAG_EXCLUDE_LIBS) @HAVE_LIBUTILS_TRUE@libknotus_la_LIBADD = $(libidn2_LIBS) \ @HAVE_LIBUTILS_TRUE@ $(libidn_LIBS) $(libnghttp2_LIBS) \ -@HAVE_LIBUTILS_TRUE@ $(libngtcp2_LIBS) $(am__append_52) +@HAVE_LIBUTILS_TRUE@ $(libngtcp2_LIBS) $(am__append_53) @HAVE_LIBUTILS_TRUE@libknotus_LIBS = libknotus.la libknot.la libdnssec.la $(libcontrib_LIBS) \ @HAVE_LIBUTILS_TRUE@ $(gnutls_LIBS) $(libedit_LIBS) @@ -2416,11 +2451,11 @@ knot_modules_whoami_la_SOURCES = knot/modules/whoami/whoami.c @HAVE_UTILS_TRUE@ utils/knsupdate/knsupdate_params.h @HAVE_UTILS_TRUE@kdig_CPPFLAGS = $(libknotus_la_CPPFLAGS) \ -@HAVE_UTILS_TRUE@ $(am__append_54) -@HAVE_UTILS_TRUE@kdig_LDADD = $(libknotus_LIBS) $(am__append_55) +@HAVE_UTILS_TRUE@ $(am__append_55) +@HAVE_UTILS_TRUE@kdig_LDADD = $(libknotus_LIBS) $(am__append_56) @HAVE_UTILS_TRUE@khost_CPPFLAGS = $(libknotus_la_CPPFLAGS) \ -@HAVE_UTILS_TRUE@ $(am__append_56) -@HAVE_UTILS_TRUE@khost_LDADD = $(libknotus_LIBS) $(am__append_57) +@HAVE_UTILS_TRUE@ $(am__append_57) +@HAVE_UTILS_TRUE@khost_LDADD = $(libknotus_LIBS) $(am__append_58) @HAVE_UTILS_TRUE@knsec3hash_CPPFLAGS = $(libknotus_la_CPPFLAGS) @HAVE_UTILS_TRUE@knsec3hash_LDADD = libknot.la libdnssec.la $(libcontrib_LIBS) @HAVE_UTILS_TRUE@knsupdate_CPPFLAGS = $(libknotus_la_CPPFLAGS) @@ -2430,17 +2465,20 @@ knot_modules_whoami_la_SOURCES = knot/modules/whoami/whoami.c @ENABLE_XDP_TRUE@@HAVE_UTILS_TRUE@ utils/kxdpgun/ip_route.h \ @ENABLE_XDP_TRUE@@HAVE_UTILS_TRUE@ utils/kxdpgun/load_queries.c \ @ENABLE_XDP_TRUE@@HAVE_UTILS_TRUE@ utils/kxdpgun/load_queries.h \ -@ENABLE_XDP_TRUE@@HAVE_UTILS_TRUE@ utils/kxdpgun/main.c +@ENABLE_XDP_TRUE@@HAVE_UTILS_TRUE@ utils/kxdpgun/main.c \ +@ENABLE_XDP_TRUE@@HAVE_UTILS_TRUE@ utils/kxdpgun/main.h \ +@ENABLE_XDP_TRUE@@HAVE_UTILS_TRUE@ utils/kxdpgun/stats.c \ +@ENABLE_XDP_TRUE@@HAVE_UTILS_TRUE@ utils/kxdpgun/stats.h @ENABLE_XDP_TRUE@@HAVE_UTILS_TRUE@kxdpgun_CPPFLAGS = \ @ENABLE_XDP_TRUE@@HAVE_UTILS_TRUE@ $(libknotus_la_CPPFLAGS) \ @ENABLE_XDP_TRUE@@HAVE_UTILS_TRUE@ $(libmnl_CFLAGS) \ -@ENABLE_XDP_TRUE@@HAVE_UTILS_TRUE@ $(am__append_59) +@ENABLE_XDP_TRUE@@HAVE_UTILS_TRUE@ $(am__append_60) @ENABLE_XDP_TRUE@@HAVE_UTILS_TRUE@kxdpgun_LDADD = libknot.la \ @ENABLE_XDP_TRUE@@HAVE_UTILS_TRUE@ $(libcontrib_LIBS) \ @ENABLE_XDP_TRUE@@HAVE_UTILS_TRUE@ $(libmnl_LIBS) \ @ENABLE_XDP_TRUE@@HAVE_UTILS_TRUE@ $(pthread_LIBS) \ -@ENABLE_XDP_TRUE@@HAVE_UTILS_TRUE@ $(am__append_60) +@ENABLE_XDP_TRUE@@HAVE_UTILS_TRUE@ $(am__append_61) @HAVE_DAEMON_TRUE@knotc_SOURCES = \ @HAVE_DAEMON_TRUE@ utils/knotc/commands.c \ @HAVE_DAEMON_TRUE@ utils/knotc/commands.h \ @@ -2890,6 +2928,10 @@ knot/modules/rrl/la-rrl.lo: knot/modules/rrl/$(am__dirstamp) \ knot/modules/rrl/$(DEPDIR)/$(am__dirstamp) knot/modules/rrl/la-functions.lo: knot/modules/rrl/$(am__dirstamp) \ knot/modules/rrl/$(DEPDIR)/$(am__dirstamp) +knot/modules/rrl/la-kru-generic.lo: knot/modules/rrl/$(am__dirstamp) \ + knot/modules/rrl/$(DEPDIR)/$(am__dirstamp) +knot/modules/rrl/la-kru-avx2.lo: knot/modules/rrl/$(am__dirstamp) \ + knot/modules/rrl/$(DEPDIR)/$(am__dirstamp) knot/modules/rrl.la: $(knot_modules_rrl_la_OBJECTS) $(knot_modules_rrl_la_DEPENDENCIES) $(EXTRA_knot_modules_rrl_la_DEPENDENCIES) knot/modules/$(am__dirstamp) $(AM_V_CCLD)$(knot_modules_rrl_la_LINK) $(am_knot_modules_rrl_la_rpath) $(knot_modules_rrl_la_OBJECTS) $(knot_modules_rrl_la_LIBADD) $(LIBS) @@ -3352,6 +3394,16 @@ libknot/probe/la-data.lo: libknot/probe/$(am__dirstamp) \ libknot/probe/$(DEPDIR)/$(am__dirstamp) libknot/probe/la-probe.lo: libknot/probe/$(am__dirstamp) \ libknot/probe/$(DEPDIR)/$(am__dirstamp) +libknot/quic/$(am__dirstamp): + @$(MKDIR_P) libknot/quic + @: > libknot/quic/$(am__dirstamp) +libknot/quic/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) libknot/quic/$(DEPDIR) + @: > libknot/quic/$(DEPDIR)/$(am__dirstamp) +libknot/quic/la-tls.lo: libknot/quic/$(am__dirstamp) \ + libknot/quic/$(DEPDIR)/$(am__dirstamp) +libknot/quic/la-tls_common.lo: libknot/quic/$(am__dirstamp) \ + libknot/quic/$(DEPDIR)/$(am__dirstamp) libknot/la-rdataset.lo: libknot/$(am__dirstamp) \ libknot/$(DEPDIR)/$(am__dirstamp) libknot/la-rrset-dump.lo: libknot/$(am__dirstamp) \ @@ -3408,12 +3460,6 @@ libknot/xdp/la-tcp.lo: libknot/xdp/$(am__dirstamp) \ libknot/xdp/$(DEPDIR)/$(am__dirstamp) libknot/xdp/la-xdp.lo: libknot/xdp/$(am__dirstamp) \ libknot/xdp/$(DEPDIR)/$(am__dirstamp) -libknot/quic/$(am__dirstamp): - @$(MKDIR_P) libknot/quic - @: > libknot/quic/$(am__dirstamp) -libknot/quic/$(DEPDIR)/$(am__dirstamp): - @$(MKDIR_P) libknot/quic/$(DEPDIR) - @: > libknot/quic/$(DEPDIR)/$(am__dirstamp) libknot/quic/la-quic.lo: libknot/quic/$(am__dirstamp) \ libknot/quic/$(DEPDIR)/$(am__dirstamp) libknot/quic/la-quic_conn.lo: libknot/quic/$(am__dirstamp) \ @@ -3566,6 +3612,9 @@ knot/events/handlers/libknotd_la-refresh.lo: \ knot/events/handlers/libknotd_la-update.lo: \ knot/events/handlers/$(am__dirstamp) \ knot/events/handlers/$(DEPDIR)/$(am__dirstamp) +knot/events/handlers/libknotd_la-validate.lo: \ + knot/events/handlers/$(am__dirstamp) \ + knot/events/handlers/$(DEPDIR)/$(am__dirstamp) knot/events/libknotd_la-replan.lo: knot/events/$(am__dirstamp) \ knot/events/$(DEPDIR)/$(am__dirstamp) knot/nameserver/$(am__dirstamp): @@ -3615,12 +3664,16 @@ knot/query/libknotd_la-query.lo: knot/query/$(am__dirstamp) \ knot/query/$(DEPDIR)/$(am__dirstamp) knot/query/libknotd_la-requestor.lo: knot/query/$(am__dirstamp) \ knot/query/$(DEPDIR)/$(am__dirstamp) +knot/query/libknotd_la-tls-requestor.lo: knot/query/$(am__dirstamp) \ + knot/query/$(DEPDIR)/$(am__dirstamp) knot/common/$(am__dirstamp): @$(MKDIR_P) knot/common @: > knot/common/$(am__dirstamp) knot/common/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) knot/common/$(DEPDIR) @: > knot/common/$(DEPDIR)/$(am__dirstamp) +knot/common/libknotd_la-dbus.lo: knot/common/$(am__dirstamp) \ + knot/common/$(DEPDIR)/$(am__dirstamp) knot/common/libknotd_la-evsched.lo: knot/common/$(am__dirstamp) \ knot/common/$(DEPDIR)/$(am__dirstamp) knot/common/libknotd_la-fdset.lo: knot/common/$(am__dirstamp) \ @@ -3792,6 +3845,12 @@ knot/modules/rrl/libknotd_la-rrl.lo: knot/modules/rrl/$(am__dirstamp) \ knot/modules/rrl/libknotd_la-functions.lo: \ knot/modules/rrl/$(am__dirstamp) \ knot/modules/rrl/$(DEPDIR)/$(am__dirstamp) +knot/modules/rrl/libknotd_la-kru-generic.lo: \ + knot/modules/rrl/$(am__dirstamp) \ + knot/modules/rrl/$(DEPDIR)/$(am__dirstamp) +knot/modules/rrl/libknotd_la-kru-avx2.lo: \ + knot/modules/rrl/$(am__dirstamp) \ + knot/modules/rrl/$(DEPDIR)/$(am__dirstamp) knot/modules/stats/libknotd_la-stats.lo: \ knot/modules/stats/$(am__dirstamp) \ knot/modules/stats/$(DEPDIR)/$(am__dirstamp) @@ -4017,6 +4076,8 @@ utils/kxdpgun/kxdpgun-load_queries.$(OBJEXT): \ utils/kxdpgun/$(DEPDIR)/$(am__dirstamp) utils/kxdpgun/kxdpgun-main.$(OBJEXT): utils/kxdpgun/$(am__dirstamp) \ utils/kxdpgun/$(DEPDIR)/$(am__dirstamp) +utils/kxdpgun/kxdpgun-stats.$(OBJEXT): utils/kxdpgun/$(am__dirstamp) \ + utils/kxdpgun/$(DEPDIR)/$(am__dirstamp) kxdpgun$(EXEEXT): $(kxdpgun_OBJECTS) $(kxdpgun_DEPENDENCIES) $(EXTRA_kxdpgun_DEPENDENCIES) @rm -f kxdpgun$(EXEEXT) @@ -4259,6 +4320,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@knot/catalog/$(DEPDIR)/libknotd_la-catalog_update.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@knot/catalog/$(DEPDIR)/libknotd_la-generate.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@knot/catalog/$(DEPDIR)/libknotd_la-interpret.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@knot/common/$(DEPDIR)/libknotd_la-dbus.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@knot/common/$(DEPDIR)/libknotd_la-evsched.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@knot/common/$(DEPDIR)/libknotd_la-fdset.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@knot/common/$(DEPDIR)/libknotd_la-log.Plo@am__quote@ # am--include-marker @@ -4306,6 +4368,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@knot/events/handlers/$(DEPDIR)/libknotd_la-notify.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@knot/events/handlers/$(DEPDIR)/libknotd_la-refresh.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@knot/events/handlers/$(DEPDIR)/libknotd_la-update.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@knot/events/handlers/$(DEPDIR)/libknotd_la-validate.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@knot/journal/$(DEPDIR)/libknotd_la-journal_basic.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@knot/journal/$(DEPDIR)/libknotd_la-journal_metadata.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@knot/journal/$(DEPDIR)/libknotd_la-journal_read.Plo@am__quote@ # am--include-marker @@ -4335,8 +4398,12 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@knot/modules/queryacl/$(DEPDIR)/la-queryacl.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@knot/modules/queryacl/$(DEPDIR)/libknotd_la-queryacl.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@knot/modules/rrl/$(DEPDIR)/la-functions.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@knot/modules/rrl/$(DEPDIR)/la-kru-avx2.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@knot/modules/rrl/$(DEPDIR)/la-kru-generic.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@knot/modules/rrl/$(DEPDIR)/la-rrl.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@knot/modules/rrl/$(DEPDIR)/libknotd_la-functions.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@knot/modules/rrl/$(DEPDIR)/libknotd_la-kru-avx2.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@knot/modules/rrl/$(DEPDIR)/libknotd_la-kru-generic.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@knot/modules/rrl/$(DEPDIR)/libknotd_la-rrl.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@knot/modules/stats/$(DEPDIR)/la-stats.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@knot/modules/stats/$(DEPDIR)/libknotd_la-stats.Plo@am__quote@ # am--include-marker @@ -4359,6 +4426,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@knot/query/$(DEPDIR)/libknotd_la-query.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@knot/query/$(DEPDIR)/libknotd_la-quic-requestor.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@knot/query/$(DEPDIR)/libknotd_la-requestor.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@knot/query/$(DEPDIR)/libknotd_la-tls-requestor.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@knot/server/$(DEPDIR)/libknotd_la-dthreads.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@knot/server/$(DEPDIR)/libknotd_la-handler.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@knot/server/$(DEPDIR)/libknotd_la-proxyv2.Plo@am__quote@ # am--include-marker @@ -4441,6 +4509,8 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@libknot/probe/$(DEPDIR)/la-probe.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@libknot/quic/$(DEPDIR)/la-quic.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@libknot/quic/$(DEPDIR)/la-quic_conn.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@libknot/quic/$(DEPDIR)/la-tls.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@libknot/quic/$(DEPDIR)/la-tls_common.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@libknot/rrtype/$(DEPDIR)/la-naptr.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@libknot/rrtype/$(DEPDIR)/la-opt.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@libknot/rrtype/$(DEPDIR)/la-tsig.Plo@am__quote@ # am--include-marker @@ -4499,6 +4569,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@utils/kxdpgun/$(DEPDIR)/kxdpgun-ip_route.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@utils/kxdpgun/$(DEPDIR)/kxdpgun-load_queries.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@utils/kxdpgun/$(DEPDIR)/kxdpgun-main.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@utils/kxdpgun/$(DEPDIR)/kxdpgun-stats.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@utils/kzonecheck/$(DEPDIR)/kzonecheck-main.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@utils/kzonecheck/$(DEPDIR)/kzonecheck-zone_check.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@utils/kzonesign/$(DEPDIR)/kzonesign-main.Po@am__quote@ # am--include-marker @@ -4624,6 +4695,20 @@ knot/modules/rrl/la-functions.lo: knot/modules/rrl/functions.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(knot_modules_rrl_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/modules/rrl/la-functions.lo `test -f 'knot/modules/rrl/functions.c' || echo '$(srcdir)/'`knot/modules/rrl/functions.c +knot/modules/rrl/la-kru-generic.lo: knot/modules/rrl/kru-generic.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(knot_modules_rrl_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/modules/rrl/la-kru-generic.lo -MD -MP -MF knot/modules/rrl/$(DEPDIR)/la-kru-generic.Tpo -c -o knot/modules/rrl/la-kru-generic.lo `test -f 'knot/modules/rrl/kru-generic.c' || echo '$(srcdir)/'`knot/modules/rrl/kru-generic.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/modules/rrl/$(DEPDIR)/la-kru-generic.Tpo knot/modules/rrl/$(DEPDIR)/la-kru-generic.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/modules/rrl/kru-generic.c' object='knot/modules/rrl/la-kru-generic.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(knot_modules_rrl_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/modules/rrl/la-kru-generic.lo `test -f 'knot/modules/rrl/kru-generic.c' || echo '$(srcdir)/'`knot/modules/rrl/kru-generic.c + +knot/modules/rrl/la-kru-avx2.lo: knot/modules/rrl/kru-avx2.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(knot_modules_rrl_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/modules/rrl/la-kru-avx2.lo -MD -MP -MF knot/modules/rrl/$(DEPDIR)/la-kru-avx2.Tpo -c -o knot/modules/rrl/la-kru-avx2.lo `test -f 'knot/modules/rrl/kru-avx2.c' || echo '$(srcdir)/'`knot/modules/rrl/kru-avx2.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/modules/rrl/$(DEPDIR)/la-kru-avx2.Tpo knot/modules/rrl/$(DEPDIR)/la-kru-avx2.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/modules/rrl/kru-avx2.c' object='knot/modules/rrl/la-kru-avx2.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(knot_modules_rrl_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/modules/rrl/la-kru-avx2.lo `test -f 'knot/modules/rrl/kru-avx2.c' || echo '$(srcdir)/'`knot/modules/rrl/kru-avx2.c + knot/modules/stats/la-stats.lo: knot/modules/stats/stats.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(knot_modules_stats_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/modules/stats/la-stats.lo -MD -MP -MF knot/modules/stats/$(DEPDIR)/la-stats.Tpo -c -o knot/modules/stats/la-stats.lo `test -f 'knot/modules/stats/stats.c' || echo '$(srcdir)/'`knot/modules/stats/stats.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/modules/stats/$(DEPDIR)/la-stats.Tpo knot/modules/stats/$(DEPDIR)/la-stats.Plo @@ -5429,6 +5514,20 @@ libknot/probe/la-probe.lo: libknot/probe/probe.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknot_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libknot/probe/la-probe.lo `test -f 'libknot/probe/probe.c' || echo '$(srcdir)/'`libknot/probe/probe.c +libknot/quic/la-tls.lo: libknot/quic/tls.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknot_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libknot/quic/la-tls.lo -MD -MP -MF libknot/quic/$(DEPDIR)/la-tls.Tpo -c -o libknot/quic/la-tls.lo `test -f 'libknot/quic/tls.c' || echo '$(srcdir)/'`libknot/quic/tls.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libknot/quic/$(DEPDIR)/la-tls.Tpo libknot/quic/$(DEPDIR)/la-tls.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libknot/quic/tls.c' object='libknot/quic/la-tls.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknot_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libknot/quic/la-tls.lo `test -f 'libknot/quic/tls.c' || echo '$(srcdir)/'`libknot/quic/tls.c + +libknot/quic/la-tls_common.lo: libknot/quic/tls_common.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknot_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libknot/quic/la-tls_common.lo -MD -MP -MF libknot/quic/$(DEPDIR)/la-tls_common.Tpo -c -o libknot/quic/la-tls_common.lo `test -f 'libknot/quic/tls_common.c' || echo '$(srcdir)/'`libknot/quic/tls_common.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libknot/quic/$(DEPDIR)/la-tls_common.Tpo libknot/quic/$(DEPDIR)/la-tls_common.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libknot/quic/tls_common.c' object='libknot/quic/la-tls_common.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknot_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libknot/quic/la-tls_common.lo `test -f 'libknot/quic/tls_common.c' || echo '$(srcdir)/'`libknot/quic/tls_common.c + libknot/la-rdataset.lo: libknot/rdataset.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknot_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libknot/la-rdataset.lo -MD -MP -MF libknot/$(DEPDIR)/la-rdataset.Tpo -c -o libknot/la-rdataset.lo `test -f 'libknot/rdataset.c' || echo '$(srcdir)/'`libknot/rdataset.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libknot/$(DEPDIR)/la-rdataset.Tpo libknot/$(DEPDIR)/la-rdataset.Plo @@ -5877,6 +5976,13 @@ knot/events/handlers/libknotd_la-update.lo: knot/events/handlers/update.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/events/handlers/libknotd_la-update.lo `test -f 'knot/events/handlers/update.c' || echo '$(srcdir)/'`knot/events/handlers/update.c +knot/events/handlers/libknotd_la-validate.lo: knot/events/handlers/validate.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/events/handlers/libknotd_la-validate.lo -MD -MP -MF knot/events/handlers/$(DEPDIR)/libknotd_la-validate.Tpo -c -o knot/events/handlers/libknotd_la-validate.lo `test -f 'knot/events/handlers/validate.c' || echo '$(srcdir)/'`knot/events/handlers/validate.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/events/handlers/$(DEPDIR)/libknotd_la-validate.Tpo knot/events/handlers/$(DEPDIR)/libknotd_la-validate.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/events/handlers/validate.c' object='knot/events/handlers/libknotd_la-validate.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/events/handlers/libknotd_la-validate.lo `test -f 'knot/events/handlers/validate.c' || echo '$(srcdir)/'`knot/events/handlers/validate.c + knot/events/libknotd_la-replan.lo: knot/events/replan.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/events/libknotd_la-replan.lo -MD -MP -MF knot/events/$(DEPDIR)/libknotd_la-replan.Tpo -c -o knot/events/libknotd_la-replan.lo `test -f 'knot/events/replan.c' || echo '$(srcdir)/'`knot/events/replan.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/events/$(DEPDIR)/libknotd_la-replan.Tpo knot/events/$(DEPDIR)/libknotd_la-replan.Plo @@ -5982,6 +6088,20 @@ knot/query/libknotd_la-requestor.lo: knot/query/requestor.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/query/libknotd_la-requestor.lo `test -f 'knot/query/requestor.c' || echo '$(srcdir)/'`knot/query/requestor.c +knot/query/libknotd_la-tls-requestor.lo: knot/query/tls-requestor.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/query/libknotd_la-tls-requestor.lo -MD -MP -MF knot/query/$(DEPDIR)/libknotd_la-tls-requestor.Tpo -c -o knot/query/libknotd_la-tls-requestor.lo `test -f 'knot/query/tls-requestor.c' || echo '$(srcdir)/'`knot/query/tls-requestor.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/query/$(DEPDIR)/libknotd_la-tls-requestor.Tpo knot/query/$(DEPDIR)/libknotd_la-tls-requestor.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/query/tls-requestor.c' object='knot/query/libknotd_la-tls-requestor.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/query/libknotd_la-tls-requestor.lo `test -f 'knot/query/tls-requestor.c' || echo '$(srcdir)/'`knot/query/tls-requestor.c + +knot/common/libknotd_la-dbus.lo: knot/common/dbus.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/common/libknotd_la-dbus.lo -MD -MP -MF knot/common/$(DEPDIR)/libknotd_la-dbus.Tpo -c -o knot/common/libknotd_la-dbus.lo `test -f 'knot/common/dbus.c' || echo '$(srcdir)/'`knot/common/dbus.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/common/$(DEPDIR)/libknotd_la-dbus.Tpo knot/common/$(DEPDIR)/libknotd_la-dbus.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/common/dbus.c' object='knot/common/libknotd_la-dbus.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/common/libknotd_la-dbus.lo `test -f 'knot/common/dbus.c' || echo '$(srcdir)/'`knot/common/dbus.c + knot/common/libknotd_la-evsched.lo: knot/common/evsched.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/common/libknotd_la-evsched.lo -MD -MP -MF knot/common/$(DEPDIR)/libknotd_la-evsched.Tpo -c -o knot/common/libknotd_la-evsched.lo `test -f 'knot/common/evsched.c' || echo '$(srcdir)/'`knot/common/evsched.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/common/$(DEPDIR)/libknotd_la-evsched.Tpo knot/common/$(DEPDIR)/libknotd_la-evsched.Plo @@ -6416,6 +6536,20 @@ knot/modules/rrl/libknotd_la-functions.lo: knot/modules/rrl/functions.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/modules/rrl/libknotd_la-functions.lo `test -f 'knot/modules/rrl/functions.c' || echo '$(srcdir)/'`knot/modules/rrl/functions.c +knot/modules/rrl/libknotd_la-kru-generic.lo: knot/modules/rrl/kru-generic.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/modules/rrl/libknotd_la-kru-generic.lo -MD -MP -MF knot/modules/rrl/$(DEPDIR)/libknotd_la-kru-generic.Tpo -c -o knot/modules/rrl/libknotd_la-kru-generic.lo `test -f 'knot/modules/rrl/kru-generic.c' || echo '$(srcdir)/'`knot/modules/rrl/kru-generic.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/modules/rrl/$(DEPDIR)/libknotd_la-kru-generic.Tpo knot/modules/rrl/$(DEPDIR)/libknotd_la-kru-generic.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/modules/rrl/kru-generic.c' object='knot/modules/rrl/libknotd_la-kru-generic.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/modules/rrl/libknotd_la-kru-generic.lo `test -f 'knot/modules/rrl/kru-generic.c' || echo '$(srcdir)/'`knot/modules/rrl/kru-generic.c + +knot/modules/rrl/libknotd_la-kru-avx2.lo: knot/modules/rrl/kru-avx2.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/modules/rrl/libknotd_la-kru-avx2.lo -MD -MP -MF knot/modules/rrl/$(DEPDIR)/libknotd_la-kru-avx2.Tpo -c -o knot/modules/rrl/libknotd_la-kru-avx2.lo `test -f 'knot/modules/rrl/kru-avx2.c' || echo '$(srcdir)/'`knot/modules/rrl/kru-avx2.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/modules/rrl/$(DEPDIR)/libknotd_la-kru-avx2.Tpo knot/modules/rrl/$(DEPDIR)/libknotd_la-kru-avx2.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='knot/modules/rrl/kru-avx2.c' object='knot/modules/rrl/libknotd_la-kru-avx2.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knot/modules/rrl/libknotd_la-kru-avx2.lo `test -f 'knot/modules/rrl/kru-avx2.c' || echo '$(srcdir)/'`knot/modules/rrl/kru-avx2.c + knot/modules/stats/libknotd_la-stats.lo: knot/modules/stats/stats.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libknotd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knot/modules/stats/libknotd_la-stats.lo -MD -MP -MF knot/modules/stats/$(DEPDIR)/libknotd_la-stats.Tpo -c -o knot/modules/stats/libknotd_la-stats.lo `test -f 'knot/modules/stats/stats.c' || echo '$(srcdir)/'`knot/modules/stats/stats.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) knot/modules/stats/$(DEPDIR)/libknotd_la-stats.Tpo knot/modules/stats/$(DEPDIR)/libknotd_la-stats.Plo @@ -6934,6 +7068,20 @@ utils/kxdpgun/kxdpgun-main.obj: utils/kxdpgun/main.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(kxdpgun_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o utils/kxdpgun/kxdpgun-main.obj `if test -f 'utils/kxdpgun/main.c'; then $(CYGPATH_W) 'utils/kxdpgun/main.c'; else $(CYGPATH_W) '$(srcdir)/utils/kxdpgun/main.c'; fi` +utils/kxdpgun/kxdpgun-stats.o: utils/kxdpgun/stats.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(kxdpgun_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT utils/kxdpgun/kxdpgun-stats.o -MD -MP -MF utils/kxdpgun/$(DEPDIR)/kxdpgun-stats.Tpo -c -o utils/kxdpgun/kxdpgun-stats.o `test -f 'utils/kxdpgun/stats.c' || echo '$(srcdir)/'`utils/kxdpgun/stats.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) utils/kxdpgun/$(DEPDIR)/kxdpgun-stats.Tpo utils/kxdpgun/$(DEPDIR)/kxdpgun-stats.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='utils/kxdpgun/stats.c' object='utils/kxdpgun/kxdpgun-stats.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(kxdpgun_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o utils/kxdpgun/kxdpgun-stats.o `test -f 'utils/kxdpgun/stats.c' || echo '$(srcdir)/'`utils/kxdpgun/stats.c + +utils/kxdpgun/kxdpgun-stats.obj: utils/kxdpgun/stats.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(kxdpgun_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT utils/kxdpgun/kxdpgun-stats.obj -MD -MP -MF utils/kxdpgun/$(DEPDIR)/kxdpgun-stats.Tpo -c -o utils/kxdpgun/kxdpgun-stats.obj `if test -f 'utils/kxdpgun/stats.c'; then $(CYGPATH_W) 'utils/kxdpgun/stats.c'; else $(CYGPATH_W) '$(srcdir)/utils/kxdpgun/stats.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) utils/kxdpgun/$(DEPDIR)/kxdpgun-stats.Tpo utils/kxdpgun/$(DEPDIR)/kxdpgun-stats.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='utils/kxdpgun/stats.c' object='utils/kxdpgun/kxdpgun-stats.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(kxdpgun_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o utils/kxdpgun/kxdpgun-stats.obj `if test -f 'utils/kxdpgun/stats.c'; then $(CYGPATH_W) 'utils/kxdpgun/stats.c'; else $(CYGPATH_W) '$(srcdir)/utils/kxdpgun/stats.c'; fi` + utils/kzonecheck/kzonecheck-main.o: utils/kzonecheck/main.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(kzonecheck_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT utils/kzonecheck/kzonecheck-main.o -MD -MP -MF utils/kzonecheck/$(DEPDIR)/kzonecheck-main.Tpo -c -o utils/kzonecheck/kzonecheck-main.o `test -f 'utils/kzonecheck/main.c' || echo '$(srcdir)/'`utils/kzonecheck/main.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) utils/kzonecheck/$(DEPDIR)/kzonecheck-main.Tpo utils/kzonecheck/$(DEPDIR)/kzonecheck-main.Po @@ -7577,6 +7725,7 @@ distclean: distclean-recursive -rm -f knot/catalog/$(DEPDIR)/libknotd_la-catalog_update.Plo -rm -f knot/catalog/$(DEPDIR)/libknotd_la-generate.Plo -rm -f knot/catalog/$(DEPDIR)/libknotd_la-interpret.Plo + -rm -f knot/common/$(DEPDIR)/libknotd_la-dbus.Plo -rm -f knot/common/$(DEPDIR)/libknotd_la-evsched.Plo -rm -f knot/common/$(DEPDIR)/libknotd_la-fdset.Plo -rm -f knot/common/$(DEPDIR)/libknotd_la-log.Plo @@ -7624,6 +7773,7 @@ distclean: distclean-recursive -rm -f knot/events/handlers/$(DEPDIR)/libknotd_la-notify.Plo -rm -f knot/events/handlers/$(DEPDIR)/libknotd_la-refresh.Plo -rm -f knot/events/handlers/$(DEPDIR)/libknotd_la-update.Plo + -rm -f knot/events/handlers/$(DEPDIR)/libknotd_la-validate.Plo -rm -f knot/journal/$(DEPDIR)/libknotd_la-journal_basic.Plo -rm -f knot/journal/$(DEPDIR)/libknotd_la-journal_metadata.Plo -rm -f knot/journal/$(DEPDIR)/libknotd_la-journal_read.Plo @@ -7653,8 +7803,12 @@ distclean: distclean-recursive -rm -f knot/modules/queryacl/$(DEPDIR)/la-queryacl.Plo -rm -f knot/modules/queryacl/$(DEPDIR)/libknotd_la-queryacl.Plo -rm -f knot/modules/rrl/$(DEPDIR)/la-functions.Plo + -rm -f knot/modules/rrl/$(DEPDIR)/la-kru-avx2.Plo + -rm -f knot/modules/rrl/$(DEPDIR)/la-kru-generic.Plo -rm -f knot/modules/rrl/$(DEPDIR)/la-rrl.Plo -rm -f knot/modules/rrl/$(DEPDIR)/libknotd_la-functions.Plo + -rm -f knot/modules/rrl/$(DEPDIR)/libknotd_la-kru-avx2.Plo + -rm -f knot/modules/rrl/$(DEPDIR)/libknotd_la-kru-generic.Plo -rm -f knot/modules/rrl/$(DEPDIR)/libknotd_la-rrl.Plo -rm -f knot/modules/stats/$(DEPDIR)/la-stats.Plo -rm -f knot/modules/stats/$(DEPDIR)/libknotd_la-stats.Plo @@ -7677,6 +7831,7 @@ distclean: distclean-recursive -rm -f knot/query/$(DEPDIR)/libknotd_la-query.Plo -rm -f knot/query/$(DEPDIR)/libknotd_la-quic-requestor.Plo -rm -f knot/query/$(DEPDIR)/libknotd_la-requestor.Plo + -rm -f knot/query/$(DEPDIR)/libknotd_la-tls-requestor.Plo -rm -f knot/server/$(DEPDIR)/libknotd_la-dthreads.Plo -rm -f knot/server/$(DEPDIR)/libknotd_la-handler.Plo -rm -f knot/server/$(DEPDIR)/libknotd_la-proxyv2.Plo @@ -7759,6 +7914,8 @@ distclean: distclean-recursive -rm -f libknot/probe/$(DEPDIR)/la-probe.Plo -rm -f libknot/quic/$(DEPDIR)/la-quic.Plo -rm -f libknot/quic/$(DEPDIR)/la-quic_conn.Plo + -rm -f libknot/quic/$(DEPDIR)/la-tls.Plo + -rm -f libknot/quic/$(DEPDIR)/la-tls_common.Plo -rm -f libknot/rrtype/$(DEPDIR)/la-naptr.Plo -rm -f libknot/rrtype/$(DEPDIR)/la-opt.Plo -rm -f libknot/rrtype/$(DEPDIR)/la-tsig.Plo @@ -7817,6 +7974,7 @@ distclean: distclean-recursive -rm -f utils/kxdpgun/$(DEPDIR)/kxdpgun-ip_route.Po -rm -f utils/kxdpgun/$(DEPDIR)/kxdpgun-load_queries.Po -rm -f utils/kxdpgun/$(DEPDIR)/kxdpgun-main.Po + -rm -f utils/kxdpgun/$(DEPDIR)/kxdpgun-stats.Po -rm -f utils/kzonecheck/$(DEPDIR)/kzonecheck-main.Po -rm -f utils/kzonecheck/$(DEPDIR)/kzonecheck-zone_check.Po -rm -f utils/kzonesign/$(DEPDIR)/kzonesign-main.Po @@ -7946,6 +8104,7 @@ maintainer-clean: maintainer-clean-recursive -rm -f knot/catalog/$(DEPDIR)/libknotd_la-catalog_update.Plo -rm -f knot/catalog/$(DEPDIR)/libknotd_la-generate.Plo -rm -f knot/catalog/$(DEPDIR)/libknotd_la-interpret.Plo + -rm -f knot/common/$(DEPDIR)/libknotd_la-dbus.Plo -rm -f knot/common/$(DEPDIR)/libknotd_la-evsched.Plo -rm -f knot/common/$(DEPDIR)/libknotd_la-fdset.Plo -rm -f knot/common/$(DEPDIR)/libknotd_la-log.Plo @@ -7993,6 +8152,7 @@ maintainer-clean: maintainer-clean-recursive -rm -f knot/events/handlers/$(DEPDIR)/libknotd_la-notify.Plo -rm -f knot/events/handlers/$(DEPDIR)/libknotd_la-refresh.Plo -rm -f knot/events/handlers/$(DEPDIR)/libknotd_la-update.Plo + -rm -f knot/events/handlers/$(DEPDIR)/libknotd_la-validate.Plo -rm -f knot/journal/$(DEPDIR)/libknotd_la-journal_basic.Plo -rm -f knot/journal/$(DEPDIR)/libknotd_la-journal_metadata.Plo -rm -f knot/journal/$(DEPDIR)/libknotd_la-journal_read.Plo @@ -8022,8 +8182,12 @@ maintainer-clean: maintainer-clean-recursive -rm -f knot/modules/queryacl/$(DEPDIR)/la-queryacl.Plo -rm -f knot/modules/queryacl/$(DEPDIR)/libknotd_la-queryacl.Plo -rm -f knot/modules/rrl/$(DEPDIR)/la-functions.Plo + -rm -f knot/modules/rrl/$(DEPDIR)/la-kru-avx2.Plo + -rm -f knot/modules/rrl/$(DEPDIR)/la-kru-generic.Plo -rm -f knot/modules/rrl/$(DEPDIR)/la-rrl.Plo -rm -f knot/modules/rrl/$(DEPDIR)/libknotd_la-functions.Plo + -rm -f knot/modules/rrl/$(DEPDIR)/libknotd_la-kru-avx2.Plo + -rm -f knot/modules/rrl/$(DEPDIR)/libknotd_la-kru-generic.Plo -rm -f knot/modules/rrl/$(DEPDIR)/libknotd_la-rrl.Plo -rm -f knot/modules/stats/$(DEPDIR)/la-stats.Plo -rm -f knot/modules/stats/$(DEPDIR)/libknotd_la-stats.Plo @@ -8046,6 +8210,7 @@ maintainer-clean: maintainer-clean-recursive -rm -f knot/query/$(DEPDIR)/libknotd_la-query.Plo -rm -f knot/query/$(DEPDIR)/libknotd_la-quic-requestor.Plo -rm -f knot/query/$(DEPDIR)/libknotd_la-requestor.Plo + -rm -f knot/query/$(DEPDIR)/libknotd_la-tls-requestor.Plo -rm -f knot/server/$(DEPDIR)/libknotd_la-dthreads.Plo -rm -f knot/server/$(DEPDIR)/libknotd_la-handler.Plo -rm -f knot/server/$(DEPDIR)/libknotd_la-proxyv2.Plo @@ -8128,6 +8293,8 @@ maintainer-clean: maintainer-clean-recursive -rm -f libknot/probe/$(DEPDIR)/la-probe.Plo -rm -f libknot/quic/$(DEPDIR)/la-quic.Plo -rm -f libknot/quic/$(DEPDIR)/la-quic_conn.Plo + -rm -f libknot/quic/$(DEPDIR)/la-tls.Plo + -rm -f libknot/quic/$(DEPDIR)/la-tls_common.Plo -rm -f libknot/rrtype/$(DEPDIR)/la-naptr.Plo -rm -f libknot/rrtype/$(DEPDIR)/la-opt.Plo -rm -f libknot/rrtype/$(DEPDIR)/la-tsig.Plo @@ -8186,6 +8353,7 @@ maintainer-clean: maintainer-clean-recursive -rm -f utils/kxdpgun/$(DEPDIR)/kxdpgun-ip_route.Po -rm -f utils/kxdpgun/$(DEPDIR)/kxdpgun-load_queries.Po -rm -f utils/kxdpgun/$(DEPDIR)/kxdpgun-main.Po + -rm -f utils/kxdpgun/$(DEPDIR)/kxdpgun-stats.Po -rm -f utils/kzonecheck/$(DEPDIR)/kzonecheck-main.Po -rm -f utils/kzonecheck/$(DEPDIR)/kzonecheck-zone_check.Po -rm -f utils/kzonesign/$(DEPDIR)/kzonesign-main.Po diff --git a/src/config.h.in b/src/config.h.in index 0be849d..3e82c0d 100644 --- a/src/config.h.in +++ b/src/config.h.in @@ -3,12 +3,6 @@ /* Define if building universal (internal helper macro) */ #undef AC_APPLE_UNIVERSAL_BUILD -/* Passed CFLAGS from environment */ -#undef CONFIGURE_CFLAGS - -/* Params passed to configure */ -#undef CONFIGURE_PARAMS - /* Configure summary */ #undef CONFIGURE_SUMMARY @@ -18,8 +12,11 @@ /* POSIX capabilities available */ #undef ENABLE_CAP_NG +/* libdbus D-Bus available */ +#undef ENABLE_DBUS_LIBDBUS + /* systemd D-Bus available */ -#undef ENABLE_DBUS +#undef ENABLE_DBUS_SYSTEMD /* PKCS #11 support available */ #undef ENABLE_PKCS11 @@ -48,12 +45,12 @@ /* Define to 1 if you have the <arpa/nameser.h> header file. */ #undef HAVE_ARPA_NAMESER_H -/* Define to 1 if you have '__atomic' functions. */ -#undef HAVE_ATOMIC - /* Define to 1 if you have the <bsd/string.h> header file. */ #undef HAVE_BSD_STRING_H +/* Define to 1 if you have C11 'atomic' functions. */ +#undef HAVE_C11_ATOMIC + /* Define if FreeBSD-like cpuset_t exists. */ #undef HAVE_CPUSET_BSD @@ -66,9 +63,6 @@ /* Define to 1 if you have the <dlfcn.h> header file. */ #undef HAVE_DLFCN_H -/* GnuTLS ED25519 support available */ -#undef HAVE_ED25519 - /* GnuTLS ED448 support available */ #undef HAVE_ED448 @@ -84,24 +78,18 @@ /* explicit_memset available */ #undef HAVE_EXPLICIT_MEMSET -/* gnutls_privkey_export_x509 available */ -#undef HAVE_EXPORT_X509 - /* Define to 1 if you have the `fgetln' function. */ #undef HAVE_FGETLN +/* Define to 1 if you have GCC-style '__atomic' functions. */ +#undef HAVE_GCC_ATOMIC + /* Define to 1 if you have the `getline' function. */ #undef HAVE_GETLINE -/* gnutls_memset available */ -#undef HAVE_GNUTLS_MEMSET - /* gnutls_early_cipher_get available */ #undef HAVE_GNUTLS_QUIC -/* GnuTLS reproducible signing available */ -#undef HAVE_GNUTLS_REPRODUCIBLE - /* Define to 1 if you have the `initgroups' function. */ #undef HAVE_INITGROUPS @@ -138,12 +126,6 @@ /* Define to 1 if you have the `setgroups' function. */ #undef HAVE_SETGROUPS -/* gnutls_privkey_sign_data2 available */ -#undef HAVE_SIGN_DATA2 - -/* Define to 1 if you have the <stdatomic.h> header file. */ -#undef HAVE_STDATOMIC_H - /* Define to 1 if you have the <stdint.h> header file. */ #undef HAVE_STDINT_H @@ -165,9 +147,6 @@ /* Define to 1 if you have the `strlcpy' function. */ #undef HAVE_STRLCPY -/* Define to 1 if you have '__sync' functions. */ -#undef HAVE_SYNC_ATOMIC - /* Define to 1 if you have the `sysctlbyname' function. */ #undef HAVE_SYSCTLBYNAME @@ -193,9 +172,6 @@ /* Define to 1 to enable IDN support */ #undef LIBIDN -/* Define to proper libidn header */ -#undef LIBIDN_HEADER - /* Define to 1 to enable DoH support */ #undef LIBNGHTTP2 diff --git a/src/contrib/Makefile.inc b/src/contrib/Makefile.inc index e1577d5..d64c2eb 100644 --- a/src/contrib/Makefile.inc +++ b/src/contrib/Makefile.inc @@ -24,6 +24,7 @@ EXTRA_DIST += \ libcontrib_la_SOURCES = \ contrib/asan.h \ + contrib/atomic.h \ contrib/base32hex.c \ contrib/base32hex.h \ contrib/base64.c \ diff --git a/src/contrib/asan.h b/src/contrib/asan.h index 5feb2c1..ef6fe66 100644 --- a/src/contrib/asan.h +++ b/src/contrib/asan.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2015 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -25,13 +25,20 @@ #if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__) void __asan_poison_memory_region(void const volatile *addr, size_t size); void __asan_unpoison_memory_region(void const volatile *addr, size_t size); +#if defined(__GNUC__) && !defined(__clang__) /* A faulty GCC workaround. */ + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wmaybe-uninitialized" +#endif #define ASAN_POISON_MEMORY_REGION(addr, size) \ __asan_poison_memory_region((addr), (size)) +#if defined(__GNUC__) && !defined(__clang__) /* End of the workaround. */ + #pragma GCC diagnostic pop +#endif #define ASAN_UNPOISON_MEMORY_REGION(addr, size) \ __asan_unpoison_memory_region((addr), (size)) -#else +#else /* __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__) */ #define ASAN_POISON_MEMORY_REGION(addr, size) \ ((void)(addr), (void)(size)) #define ASAN_UNPOISON_MEMORY_REGION(addr, size) \ ((void)(addr), (void)(size)) -#endif +#endif /* __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__) */ diff --git a/src/contrib/atomic.h b/src/contrib/atomic.h new file mode 100644 index 0000000..b8dace1 --- /dev/null +++ b/src/contrib/atomic.h @@ -0,0 +1,73 @@ +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + 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 3 of the License, 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 <https://www.gnu.org/licenses/>. + */ + +/*! + * \brief C11 atomic operations with fallbacks. + */ + +#pragma once + +#ifdef HAVE_C11_ATOMIC /* C11 */ + #define KNOT_HAVE_ATOMIC + + #include <stdatomic.h> + + #define ATOMIC_SET(dst, val) atomic_store_explicit(&(dst), (val), memory_order_relaxed) + #define ATOMIC_GET(src) atomic_load_explicit(&(src), memory_order_relaxed) + #define ATOMIC_ADD(dst, val) (void)atomic_fetch_add_explicit(&(dst), (val), memory_order_relaxed) + #define ATOMIC_SUB(dst, val) (void)atomic_fetch_sub_explicit(&(dst), (val), memory_order_relaxed) + #define ATOMIC_XCHG(dst, val) atomic_exchange_explicit(&(dst), (val), memory_order_relaxed) + + typedef atomic_uint_fast16_t knot_atomic_uint16_t; + typedef atomic_uint_fast64_t knot_atomic_uint64_t; + typedef atomic_size_t knot_atomic_size_t; + typedef _Atomic (void *) knot_atomic_ptr_t; + typedef atomic_bool knot_atomic_bool; +#elif defined(HAVE_GCC_ATOMIC) /* GCC __atomic */ + #define KNOT_HAVE_ATOMIC + + #include <stdint.h> + #include <stdbool.h> + + #define ATOMIC_SET(dst, val) __atomic_store_n(&(dst), (val), __ATOMIC_RELAXED) + #define ATOMIC_GET(src) __atomic_load_n(&(src), __ATOMIC_RELAXED) + #define ATOMIC_ADD(dst, val) __atomic_add_fetch(&(dst), (val), __ATOMIC_RELAXED) + #define ATOMIC_SUB(dst, val) __atomic_sub_fetch(&(dst), (val), __ATOMIC_RELAXED) + #define ATOMIC_XCHG(dst, val) __atomic_exchange_n(&(dst), (val), __ATOMIC_RELAXED) + + typedef uint16_t knot_atomic_uint16_t; + typedef uint64_t knot_atomic_uint64_t; + typedef size_t knot_atomic_size_t; + typedef void* knot_atomic_ptr_t; + typedef bool knot_atomic_bool; +#else /* Fallback, non-atomic. */ + #warning "Atomic operations not availabe, using unreliable replacement." + + #include <stdint.h> + #include <stdbool.h> + + #define ATOMIC_SET(dst, val) ((dst) = (val)) + #define ATOMIC_GET(src) (src) + #define ATOMIC_ADD(dst, val) ((dst) += (val)) + #define ATOMIC_SUB(dst, val) ((dst) -= (val)) + #define ATOMIC_XCHG(dst, val) ({ __typeof__ (dst) _z = (dst); (dst) = (val); _z; }) + + typedef uint16_t knot_atomic_uint16_t; + typedef uint64_t knot_atomic_uint64_t; + typedef size_t knot_atomic_size_t; + typedef void* knot_atomic_ptr_t; + typedef bool knot_atomic_bool; +#endif diff --git a/src/contrib/files.c b/src/contrib/files.c index 5b38469..f3a4b78 100644 --- a/src/contrib/files.c +++ b/src/contrib/files.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -92,16 +92,29 @@ static int remove_file(const char *path, const struct stat *stat, int type, stru { (void)stat; (void)ftw; - if (type == FTW_DP) { + + switch (type) { + case FTW_D: + case FTW_DNR: + case FTW_DP: return rmdir(path); - } else { + default: return unlink(path); } } -bool remove_path(const char *path) +static int remove_in_dir(const char *path, const struct stat *stat, int type, struct FTW *ftw) +{ + return (ftw->level > 0) ? remove_file(path, stat, type, ftw) : 0; +} + +int remove_path(const char *path, bool keep_apex) { - return (0 == nftw(path, remove_file, 1, FTW_DEPTH | FTW_PHYS)); + if (0 != nftw(path, keep_apex ? remove_in_dir : remove_file, + 1, FTW_DEPTH | FTW_PHYS)) { + return knot_map_errno(); + } + return KNOT_EOK; } int make_dir(const char *path, mode_t mode, bool ignore_existing) diff --git a/src/contrib/files.h b/src/contrib/files.h index c505ac8..4250a47 100644 --- a/src/contrib/files.h +++ b/src/contrib/files.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -52,9 +52,12 @@ bool same_path(const char *path1, const char *path2); /*! * \brief Delete file or directory (recursive). * - * \return true on success, false when one or more files failed to be removed. + * \param[in] path Absolute path or a relative path suffix; a string. + * \param[in] keep_apex If true, don't remove the starting point (apex). + * + * \return KNOT_E* */ -bool remove_path(const char *path); +int remove_path(const char *path, bool keep_apex); /*! * Equivalent to mkdir(2), can succeed if the directory already exists. diff --git a/src/contrib/json.c b/src/contrib/json.c index d44da87..5173f90 100644 --- a/src/contrib/json.c +++ b/src/contrib/json.c @@ -217,6 +217,13 @@ void jsonw_int(jsonw_t *w, const char *key, int value) fprintf(w->out, "%d", value); } +void jsonw_double(jsonw_t *w, const char *key, double value) +{ + assert(w); + + align_key(w, key); + fprintf(w->out, "%.4f", value); +} void jsonw_bool(jsonw_t *w, const char *key, bool value) { diff --git a/src/contrib/json.h b/src/contrib/json.h index cf8abe6..17513bc 100644 --- a/src/contrib/json.h +++ b/src/contrib/json.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -82,6 +82,11 @@ void jsonw_ulong(jsonw_t *w, const char *key, unsigned long value); void jsonw_int(jsonw_t *w, const char *key, int value); /*! + * Write double as JSON. + */ +void jsonw_double(jsonw_t *w, const char *key, double value); + +/*! * Write boolean value as JSON. */ void jsonw_bool(jsonw_t *w, const char *key, bool value); diff --git a/src/contrib/mempattern.c b/src/contrib/mempattern.c index f57139d..f86f0ac 100644 --- a/src/contrib/mempattern.c +++ b/src/contrib/mempattern.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -114,9 +114,15 @@ void mm_ctx_init(knot_mm_t *mm) mm->free = free; } +// UBSAN type punning workaround +static void *mp_alloc_wrap(void *ctx, size_t size) +{ + return mp_alloc(ctx, size); +} + void mm_ctx_mempool(knot_mm_t *mm, size_t chunk_size) { mm->ctx = mp_new(chunk_size); - mm->alloc = (knot_mm_alloc_t)mp_alloc; + mm->alloc = mp_alloc_wrap; mm->free = mm_nofree; } diff --git a/src/contrib/spinlock.h b/src/contrib/spinlock.h index 837f500..a7ec5ec 100644 --- a/src/contrib/spinlock.h +++ b/src/contrib/spinlock.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -15,48 +15,23 @@ */ /*! - * \brief Multiplatform spinlock. + * \brief A C11 spinlock (POSIX pthread spinlock as a fallback). */ #pragma once #if (__STDC_VERSION__ >= 201112L) && !defined(__STDC_NO_ATOMICS__) -/* Not tested and activated yet. */ -/* #define HAVE_STDATOMIC */ -#endif - -#if defined(__APPLE__) -# if defined(MAC_OS_X_VERSION_10_12) || \ - MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_12 -# define APPLE_SPIN_NEW -# else -# define APPLE_SPIN_OLD -# endif /* MAC_OS_X_VERSION_10_12 ... */ -#endif /* __APPLE__ */ - -#if defined(HAVE_SYNC_ATOMIC) || defined(HAVE_ATOMIC) -# include <stdbool.h> -#elif defined(HAVE_STDATOMIC) -# include <stdbool.h> -# include <stdatomic.h> -#elif defined(APPLE_SPIN_NEW) -# include <os/lock.h> -#elif defined(APPLE_SPIN_OLD) -# include <libkern/OSAtomic.h> + #define HAVE_STDATOMIC + #include <stdatomic.h> + #include <stdbool.h> #else /* POSIX pthread spinlock. */ -# include <pthread.h> + #include <pthread.h> #endif /*! \brief Spinlock lock variable type. */ typedef -#if defined(HAVE_SYNC_ATOMIC) || defined(HAVE_ATOMIC) - bool /*!< Spinlock lock - a simple & fast atomic version. */ -#elif defined(HAVE_STDATOMIC) +#if defined(HAVE_STDATOMIC) atomic_bool /*!< Spinlock lock - a simple & fast atomic version, C11 */ -#elif defined(APPLE_SPIN_NEW) - os_unfair_lock /*!< Spinlock lock - a newer macOS version (macOS >= 10.12). */ -#elif defined(APPLE_SPIN_OLD) - OSSpinLock /*!< Spinlock lock - an older macOS version (macOS < 10.12). */ #else /* POSIX */ pthread_spinlock_t /*!< Spinlock lock - a POSIX pthread version. */ #endif @@ -65,14 +40,8 @@ typedef /*! \brief Initialize the spinlock pointed to by the parameter "lock". */ static inline void knot_spin_init(knot_spin_t *lock) { -#if defined(HAVE_SYNC_ATOMIC) || defined(HAVE_ATOMIC) - *lock = false; -#elif defined(HAVE_STDATOMIC) +#if defined(HAVE_STDATOMIC) atomic_init(lock, false); -#elif defined(APPLE_SPIN_NEW) - *lock = OS_UNFAIR_LOCK_INIT; -#elif defined(APPLE_SPIN_OLD) - *lock = OS_SPINLOCK_INIT; #else /* POSIX */ pthread_spin_init(lock, PTHREAD_PROCESS_PRIVATE); #endif @@ -81,8 +50,7 @@ static inline void knot_spin_init(knot_spin_t *lock) /*! \brief Destroy the spinlock pointed to by the parameter "lock". */ static inline void knot_spin_destroy(knot_spin_t *lock) { -#if defined(HAVE_SYNC_ATOMIC) || defined(HAVE_ATOMIC) || defined(HAVE_STDATOMIC) || \ - defined(APPLE_SPIN_NEW) || defined(APPLE_SPIN_OLD) +#if defined(HAVE_STDATOMIC) /* Nothing needed here. */ #else /* POSIX */ pthread_spin_destroy(lock); @@ -92,23 +60,11 @@ static inline void knot_spin_destroy(knot_spin_t *lock) /*! \brief Lock the spinlock pointed to by the parameter "lock". */ static inline void knot_spin_lock(knot_spin_t *lock) { -#if defined(HAVE_SYNC_ATOMIC) - while (__sync_lock_test_and_set(lock, 1)) { - } -#elif defined(HAVE_ATOMIC) - int expected = 0; - while (!__atomic_compare_exchange_n(lock, &expected, 1, false, __ATOMIC_RELAXED, __ATOMIC_RELAXED)) { - expected = 0; - } -#elif defined(HAVE_STDATOMIC) - int expected = 0; - while (!atomic_compare_exchange_strong(lock, &expected, false)) { - expected = 0; +#if defined(HAVE_STDATOMIC) + bool expected = false; + while (!atomic_compare_exchange_strong(lock, &expected, true)) { + expected = false; } -#elif defined(APPLE_SPIN_NEW) - os_unfair_lock_lock(lock); -#elif defined(APPLE_SPIN_OLD) - OSSpinLockLock(lock); #else /* POSIX */ pthread_spin_lock(lock); #endif @@ -117,16 +73,8 @@ static inline void knot_spin_lock(knot_spin_t *lock) /*! \brief Unlock the spinlock pointed to by the parameter "lock". */ static inline void knot_spin_unlock(knot_spin_t *lock) { -#if defined(HAVE_SYNC_ATOMIC) - __sync_lock_release(lock); -#elif defined(HAVE_ATOMIC) - __atomic_clear(lock, __ATOMIC_RELAXED); -#elif defined(HAVE_STDATOMIC) +#if defined(HAVE_STDATOMIC) atomic_store(lock, false); -#elif defined(APPLE_SPIN_NEW) - os_unfair_lock_unlock(lock); -#elif defined(APPLE_SPIN_OLD) - OSSpinLockUnlock(lock); #else /* POSIX */ pthread_spin_unlock(lock); #endif diff --git a/src/contrib/string.c b/src/contrib/string.c index 272116e..6fa2d0a 100644 --- a/src/contrib/string.c +++ b/src/contrib/string.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -26,16 +26,16 @@ /* #include <string.h> is needed. */ #elif defined(HAVE_EXPLICIT_MEMSET) /* #include <string.h> is needed. */ -#elif defined(HAVE_GNUTLS_MEMSET) - #include <gnutls/gnutls.h> #else - #define USE_CUSTOM_MEMSET + #include <gnutls/gnutls.h> #endif #include "contrib/string.h" #include "contrib/ctype.h" #include "contrib/tolower.h" +const char *configure_summary = CONFIGURE_SUMMARY; + uint8_t *memdup(const uint8_t *data, size_t data_size) { uint8_t *result = (uint8_t *)malloc(data_size); @@ -137,11 +137,6 @@ int const_time_memcmp(const void *s1, const void *s2, size_t n) return equal; } -#if defined(USE_CUSTOM_MEMSET) -typedef void *(*memset_t)(void *, int, size_t); -static volatile memset_t volatile_memset = memset; -#endif - void *memzero(void *s, size_t n) { #if defined(HAVE_EXPLICIT_BZERO) /* In OpenBSD since 5.5. */ @@ -161,14 +156,9 @@ void *memzero(void *s, size_t n) return s; #elif defined(HAVE_EXPLICIT_MEMSET) /* In NetBSD since 7.0. */ return explicit_memset(s, 0, n); -#elif defined(HAVE_GNUTLS_MEMSET) /* In GnuTLS since 3.4.0. */ +#else gnutls_memset(s, 0, n); return s; -#else /* Knot custom solution as a fallback. */ - /* Warning: the use of the return value is *probably* needed - * so as to avoid the volatile_memset() to be optimized out. - */ - return volatile_memset(s, 0, n); #endif } diff --git a/src/contrib/string.h b/src/contrib/string.h index ad3c990..3e113b1 100644 --- a/src/contrib/string.h +++ b/src/contrib/string.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -24,6 +24,8 @@ #include <stddef.h> #include <stdint.h> +extern const char *configure_summary; + /*! * \brief Create a copy of a binary buffer. * diff --git a/src/contrib/time.h b/src/contrib/time.h index 20d241e..b12b366 100644 --- a/src/contrib/time.h +++ b/src/contrib/time.h @@ -88,6 +88,11 @@ inline static int knot_time_cmp(knot_time_t a, knot_time_t b) { return (a == b ? 0 : 1) * ((a && b) == 0 ? -1 : 1) * (a < b ? -1 : 1); } +inline static bool knot_time_lt (knot_time_t a, knot_time_t b) { return knot_time_cmp(a, b) < 0; } +inline static bool knot_time_leq(knot_time_t a, knot_time_t b) { return knot_time_cmp(a, b) <= 0; } +inline static bool knot_time_eq (knot_time_t a, knot_time_t b) { return knot_time_cmp(a, b) == 0; } +inline static bool knot_time_geq(knot_time_t a, knot_time_t b) { return knot_time_cmp(a, b) >= 0; } +inline static bool knot_time_gt (knot_time_t a, knot_time_t b) { return knot_time_cmp(a, b) > 0; } /*! * \brief Return the smaller (=earlier) from given two timestamps. diff --git a/src/knot/Makefile.inc b/src/knot/Makefile.inc index f67fe7f..0cbc9f3 100644 --- a/src/knot/Makefile.inc +++ b/src/knot/Makefile.inc @@ -1,12 +1,11 @@ libknotd_la_CPPFLAGS = $(AM_CPPFLAGS) $(CFLAG_VISIBILITY) $(libkqueue_CFLAGS) \ $(liburcu_CFLAGS) $(lmdb_CFLAGS) $(systemd_CFLAGS) \ - $(gnutls_CFLAGS) $(libngtcp2_CFLAGS) -DKNOTD_MOD_STATIC + $(libdbus_CFLAGS) $(gnutls_CFLAGS) -DKNOTD_MOD_STATIC libknotd_la_LDFLAGS = $(AM_LDFLAGS) -export-symbols-regex '^knotd_' -libknotd_la_LIBADD = $(dlopen_LIBS) $(libkqueue_LIBS) $(pthread_LIBS) \ - $(libngtcp2_LIBS) +libknotd_la_LIBADD = $(dlopen_LIBS) $(libkqueue_LIBS) $(pthread_LIBS) libknotd_LIBS = libknotd.la libknot.la libdnssec.la libzscanner.la \ $(libcontrib_LIBS) $(liburcu_LIBS) $(lmdb_LIBS) \ - $(systemd_LIBS) $(gnutls_LIBS) + $(systemd_LIBS) $(libdbus_LIBS) $(gnutls_LIBS) if EMBEDDED_LIBNGTCP2 libknotd_la_LIBADD += $(libembngtcp2_LIBS) @@ -93,6 +92,7 @@ libknotd_la_SOURCES = \ knot/events/handlers/notify.c \ knot/events/handlers/refresh.c \ knot/events/handlers/update.c \ + knot/events/handlers/validate.c \ knot/events/replan.c \ knot/events/replan.h \ knot/nameserver/axfr.c \ @@ -125,6 +125,10 @@ libknotd_la_SOURCES = \ knot/query/query.h \ knot/query/requestor.c \ knot/query/requestor.h \ + knot/query/tls-requestor.c \ + knot/query/tls-requestor.h \ + knot/common/dbus.c \ + knot/common/dbus.h \ knot/common/evsched.c \ knot/common/evsched.h \ knot/common/fdset.c \ diff --git a/src/knot/catalog/catalog_db.c b/src/knot/catalog/catalog_db.c index b483f4d..2ea776f 100644 --- a/src/knot/catalog/catalog_db.c +++ b/src/knot/catalog/catalog_db.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -44,7 +44,7 @@ int catalog_bailiwick_shift(const knot_dname_t *subname, const knot_dname_t *nam if (*res == '\0') { return -1; } - res = knot_wire_next_label(res, NULL); + res = knot_dname_next_label(res); } return res - subname; } diff --git a/src/knot/catalog/catalog_update.c b/src/knot/catalog/catalog_update.c index edfd8c5..71b7dbe 100644 --- a/src/knot/catalog/catalog_update.c +++ b/src/knot/catalog/catalog_update.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -132,7 +132,7 @@ static const knot_dname_t *get_uniq(const knot_dname_t *ptr_owner, int labels = knot_dname_labels(ptr_owner, NULL); labels -= knot_dname_labels(catz, NULL); assert(labels >= 2); - return ptr_owner + knot_dname_prefixlen(ptr_owner, labels - 2, NULL); + return ptr_owner + knot_dname_prefixlen(ptr_owner, labels - 2); } static bool same_uniq(const knot_dname_t *owner1, const knot_dname_t *catz1, diff --git a/src/knot/catalog/interpret.c b/src/knot/catalog/interpret.c index 7337105..3e8e5db 100644 --- a/src/knot/catalog/interpret.c +++ b/src/knot/catalog/interpret.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -105,7 +105,7 @@ static const knot_dname_t *property_get_member(const zone_node_t *prop_node, knot_rdataset_t *ptr = node_rdataset(prop_node->parent, KNOT_RRTYPE_PTR); if (ptr == NULL) { // fallback: search in provided complete zone contents - const knot_dname_t *memb_name = knot_wire_next_label(prop_node->owner, NULL); + const knot_dname_t *memb_name = knot_dname_next_label(prop_node->owner); const zone_node_t *memb_node = zone_contents_find_node(complete_conts, memb_name); ptr = node_rdataset(memb_node, KNOT_RRTYPE_PTR); if (memb_node != NULL) { diff --git a/src/knot/common/dbus.c b/src/knot/common/dbus.c new file mode 100644 index 0000000..38ae5fa --- /dev/null +++ b/src/knot/common/dbus.c @@ -0,0 +1,243 @@ +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + 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 3 of the License, 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 <https://www.gnu.org/licenses/>. + */ + +#include <stdarg.h> + +#include "knot/common/dbus.h" +#include "knot/common/log.h" + +#define ENABLE_DBUS (ENABLE_DBUS_SYSTEMD | ENABLE_DBUS_LIBDBUS) + +#if defined(ENABLE_DBUS_SYSTEMD) + +#include <systemd/sd-bus.h> +#define VALUE_OF(x) (x) +typedef sd_bus * dbus_ctx_t; + +#elif defined(ENABLE_DBUS_LIBDBUS) + +#include <assert.h> +#include <dbus/dbus.h> +#define VALUE_OF(x) (&(x)) +typedef DBusConnection * dbus_ctx_t; + +#else + +typedef struct {} * dbus_ctx_t; // Dummy + +#endif // ENABLE_DBUS_LIBDBUS + +static dbus_ctx_t _dbus = NULL; + +int dbus_open(void) +{ + if (_dbus != NULL) { + return KNOT_EOK; + } +#if defined(ENABLE_DBUS_SYSTEMD) + int ret = sd_bus_open_system(&_dbus); + if (ret < 0) { + goto error_systemd; + } + + /* Take a well-known service name so that clients can find us. */ + ret = sd_bus_request_name(_dbus, KNOT_DBUS_NAME, 0); + if (ret < 0) { + goto error_systemd; + } + + log_info("d-bus: connected to system bus"); + return KNOT_EOK; +error_systemd: + log_error("d-bus: failed to open system bus (%s)", knot_strerror(ret)); + dbus_close(); + return ret; +#elif defined(ENABLE_DBUS_LIBDBUS) + DBusError err; + dbus_error_init(&err); + + _dbus = dbus_bus_get(DBUS_BUS_SYSTEM, &err); + if (dbus_error_is_set(&err) == TRUE) { + goto error_libdbus; + } + + /* Take a well-known service name so that clients can find us. */ + dbus_bus_request_name(_dbus, KNOT_DBUS_NAME, 0, &err); + if (dbus_error_is_set(&err) == TRUE) { + goto error_libdbus; + } + + dbus_error_free(&err); + log_info("d-bus: connected to system bus"); + return KNOT_EOK; +error_libdbus: + log_error("d-bus: failed to open system bus (%s)", err.message); + dbus_error_free(&err); + dbus_close(); + return KNOT_ERROR; +#endif + log_error("d-bus: not supported"); + return KNOT_ENOTSUP; +} + +void dbus_close(void) +{ + if (_dbus == NULL) { + return; + } +#if defined(ENABLE_DBUS_SYSTEMD) + _dbus = sd_bus_unref(_dbus); +#elif defined(ENABLE_DBUS_LIBDBUS) + dbus_connection_unref(_dbus); + _dbus = NULL; +#endif // ENABLE_DBUS_LIBDBUS +} + +#if ENABLE_DBUS +static void emit_event(const char *event, char *first_arg_type, ...) +{ + int ret = KNOT_ENOENT; + if (_dbus == NULL) { + goto failed; + } + +#if defined(ENABLE_DBUS_SYSTEMD) + sd_bus_message *msg = NULL; + ret = sd_bus_message_new_signal(_dbus, &msg, KNOT_DBUS_PATH, + KNOT_DBUS_NAME".events", event); + if (ret < 0) { + goto failed; + } + + va_list args; + va_start(args, first_arg_type); + ret = sd_bus_message_appendv(msg, first_arg_type, args); + if (ret < 0) { + sd_bus_message_unref(msg); + va_end(args); + goto failed; + } + /* + * \note sd_bus_message_send(msg) or even sd_bus_emit_signalv() can + * be used with a newer systemd. + */ + ret = sd_bus_send(sd_bus_message_get_bus(msg), msg, NULL); + if (ret < 0) { + sd_bus_message_unref(msg); + va_end(args); + goto failed; + } + va_end(args); +#elif defined(ENABLE_DBUS_LIBDBUS) + DBusMessage *msg = NULL; + msg = dbus_message_new_signal(KNOT_DBUS_PATH, KNOT_DBUS_NAME".events", + event); + if (msg == NULL) { + ret = KNOT_ENOMEM; + goto failed; + } + + /* + * \note This loop considers only basic data types; composite ones, + * such as arrays, result in undefined behavior. + */ + va_list args; + va_start(args, first_arg_type); + for (const char *type = first_arg_type; *type; ++type) { + dbus_bool_t bret = dbus_message_append_args(msg, *type, + va_arg(args, void *), + DBUS_TYPE_INVALID); + if (bret == FALSE) { + dbus_message_unref(msg); + va_end(args); + assert(0); // Read note + ret = KNOT_EINVAL; + goto failed; + } + } + + if (dbus_connection_send(_dbus, msg, NULL) == 0) { + dbus_message_unref(msg); + va_end(args); + ret = KNOT_NET_ESEND; + goto failed; + } + dbus_message_unref(msg); + va_end(args); +#endif // ENABLE_DBUS_LIBDBUS + return; +failed: + log_error("d-bus: failed to emit signal '%s' (%s)", event, knot_strerror(ret)); +} +#endif // ENABLE_DBUS + +void dbus_emit_running(bool up) +{ +#if ENABLE_DBUS + emit_event(up ? KNOT_BUS_EVENT_STARTED : KNOT_BUS_EVENT_STOPPED, ""); +#endif // ENABLE_DBUS +} + +void dbus_emit_zone_updated(const knot_dname_t *zone_name, uint32_t serial) +{ +#if ENABLE_DBUS + knot_dname_txt_storage_t buff; + char *zone_str = knot_dname_to_str(buff, zone_name, sizeof(buff)); + if (zone_str != NULL) { + emit_event(KNOT_BUS_EVENT_ZONE_UPD, "su", VALUE_OF(zone_str), + VALUE_OF(serial)); + } +#endif // ENABLE_DBUS +} + +void dbus_emit_keys_updated(const knot_dname_t *zone_name) +{ +#if ENABLE_DBUS + knot_dname_txt_storage_t buff; + char *zone_str = knot_dname_to_str(buff, zone_name, sizeof(buff)); + if (zone_str != NULL) { + emit_event(KNOT_BUS_EVENT_ZONE_KEYS_UPD, "s", + VALUE_OF(zone_str)); + } +#endif // ENABLE_DBUS +} + +void dbus_emit_zone_submission(const knot_dname_t *zone_name, uint16_t keytag, + const char *keyid) +{ +#if ENABLE_DBUS + knot_dname_txt_storage_t buff; + char *zone_str = knot_dname_to_str(buff, zone_name, sizeof(buff)); + if (zone_str != NULL) { + emit_event(KNOT_BUS_EVENT_ZONE_KSK_SUBM, "sqs", + VALUE_OF(zone_str), VALUE_OF(keytag), + VALUE_OF(keyid)); + } +#endif // ENABLE_DBUS +} + +void dbus_emit_zone_invalid(const knot_dname_t *zone_name, uint32_t remaining_secs) +{ +#if ENABLE_DBUS + knot_dname_txt_storage_t buff; + char *zone_str = knot_dname_to_str(buff, zone_name, sizeof(buff)); + if (zone_str != NULL) { + emit_event(KNOT_BUS_EVENT_ZONE_INVALID, "su", + VALUE_OF(zone_str), + VALUE_OF(remaining_secs)); + } +#endif // ENABLE_DBUS +} diff --git a/src/knot/common/dbus.h b/src/knot/common/dbus.h new file mode 100644 index 0000000..3a529f3 --- /dev/null +++ b/src/knot/common/dbus.h @@ -0,0 +1,86 @@ +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + 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 3 of the License, 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 <https://www.gnu.org/licenses/>. + */ + +/*! + * \brief D-Bus API wrappers. + */ + +#pragma once + +#include "libknot/libknot.h" + +#define KNOT_DBUS_NAME "cz.nic.knotd" +#define KNOT_DBUS_PATH "/cz/nic/knotd" + +#define KNOT_BUS_EVENT_STARTED "started" +#define KNOT_BUS_EVENT_STOPPED "stopped" +#define KNOT_BUS_EVENT_ZONE_UPD "zone_updated" +#define KNOT_BUS_EVENT_ZONE_KEYS_UPD "keys_updated" +#define KNOT_BUS_EVENT_ZONE_KSK_SUBM "zone_ksk_submission" +#define KNOT_BUS_EVENT_ZONE_INVALID "zone_dnssec_invalid" + +/*! + * \brief Creates unique D-Bus sender reference (common for whole process). + * + * \retval KNOT_EOK on successful create of reference. + * \retval Negative value on error. + */ +int dbus_open(void); + +/*! + * \brief Closes D-Bus. + */ +void dbus_close(void); + +/*! + * \brief Emit event signal for started daemon. + * + * \param up Indication if the server has been started. + */ +void dbus_emit_running(bool up); + +/*! + * \brief Emit event signal for updated zones. + * + * \param zone_name Zone name. + * \param serial Current zone SOA serial. + */ +void dbus_emit_zone_updated(const knot_dname_t *zone_name, uint32_t serial); + +/*! + * \brief Emit event signal for updated DNSSEC key set. + * + * \param zone_name Zone name. + */ +void dbus_emit_keys_updated(const knot_dname_t *zone_name); + +/*! + * \brief Emit event signal for KSK submission. + * + * \param zone_name Zone name. + * \param keytag Keytag of the ready key. + * \param keyid KASP id of the ready key. + */ +void dbus_emit_zone_submission(const knot_dname_t *zone_name, uint16_t keytag, + const char *keyid); + +/*! + * \brief Emit event signal for failed DNSSEC validation. + * + * \param zone_name Zone name. + * \param remaining_secs Remaining time until a RRSIG expires. + */ +void dbus_emit_zone_invalid(const knot_dname_t *zone_name, uint32_t remaining_secs); diff --git a/src/knot/common/fdset.c b/src/knot/common/fdset.c index a0a0212..2bf4113 100644 --- a/src/knot/common/fdset.c +++ b/src/knot/common/fdset.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -35,6 +35,7 @@ static int fdset_resize(fdset_t *set, const unsigned size) assert(set); MEM_RESIZE(set->ctx, size); + MEM_RESIZE(set->ctx2, size); MEM_RESIZE(set->timeout, size); #if defined(HAVE_EPOLL) || defined(HAVE_KQUEUE) MEM_RESIZE(set->ev, size); @@ -80,6 +81,7 @@ void fdset_clear(fdset_t *set) } free(set->ctx); + free(set->ctx2); free(set->timeout); #if defined(HAVE_EPOLL) || defined(HAVE_KQUEUE) free(set->ev); @@ -104,6 +106,7 @@ int fdset_add(fdset_t *set, const int fd, const fdset_event_t events, void *ctx) const int idx = set->n++; set->ctx[idx] = ctx; + set->ctx2[idx] = NULL; set->timeout[idx] = 0; #ifdef HAVE_EPOLL set->ev[idx].data.fd = fd; @@ -164,6 +167,7 @@ int fdset_remove(fdset_t *set, const unsigned idx) /* Nothing else if it is the last one. Move last -> i if some remain. */ if (idx < last) { set->ctx[idx] = set->ctx[last]; + set->ctx2[idx] = set->ctx2[last]; set->timeout[idx] = set->timeout[last]; #if defined(HAVE_EPOLL) || defined (HAVE_KQUEUE) set->ev[idx] = set->ev[last]; @@ -326,8 +330,7 @@ void fdset_sweep(fdset_t *set, const fdset_sweep_cb_t cb, void *data) while (idx < set->n) { /* Check sweep state, remove if requested. */ if (set->timeout[idx] > 0 && set->timeout[idx] <= now.tv_sec) { - const int fd = fdset_get_fd(set, idx); - if (cb(set, fd, data) == FDSET_SWEEP) { + if (cb(set, idx, data) == FDSET_SWEEP) { (void)fdset_remove(set, idx); continue; } diff --git a/src/knot/common/fdset.h b/src/knot/common/fdset.h index e0c3dbe..81ec7a8 100644 --- a/src/knot/common/fdset.h +++ b/src/knot/common/fdset.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -45,6 +45,7 @@ typedef struct { unsigned n; /*!< Active fds. */ unsigned size; /*!< Array size (allocated). */ void **ctx; /*!< Context for each fd. */ + void **ctx2; /*!< Another context for each fd. */ time_t *timeout; /*!< Timeout for each fd (seconds precision). */ #if defined(HAVE_EPOLL) || defined(HAVE_KQUEUE) #ifdef HAVE_EPOLL @@ -271,6 +272,16 @@ inline static void *fdset_it_get_ctx(const fdset_it_t *it) } /*! + * \brief Get a read/write pointer on (void *) second context. + */ +inline static void **fdset_ctx2(const fdset_t *set, const unsigned idx) +{ + assert(set && idx < set->n); + + return &set->ctx2[idx]; +} + +/*! * \brief Move iterator on next received event. * * \param it Target iterator. diff --git a/src/knot/common/stats.c b/src/knot/common/stats.c index 79c0f23..da31e3d 100644 --- a/src/knot/common/stats.c +++ b/src/knot/common/stats.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -24,140 +24,168 @@ #include "knot/common/stats.h" #include "knot/common/log.h" #include "knot/nameserver/query_module.h" +#include "libknot/xdp.h" -struct { - bool active_dumper; - pthread_t dumper; - uint32_t timer; - server_t *server; -} stats = { 0 }; - -typedef struct { - FILE *fd; - const list_t *query_modules; - const knot_dname_t *zone; - unsigned threads; - int level; - bool zone_emitted; - bool zone_name_emitted; - bool module_emitted; -} dump_ctx_t; - -#define DUMP_STR(fd, level, name, ...) do { \ - fprintf(fd, "%-.*s"name":\n", level, " ", ##__VA_ARGS__); \ -} while (0) - -#define DUMP_CTR(fd, level, name, idx, val) do { \ - fprintf(fd, "%-.*s"name": %"PRIu64"\n", level, " ", idx, val); \ -} while (0) - -static uint64_t server_zone_count(server_t *server) +static uint64_t stats_get_counter(knot_atomic_uint64_t **stats_vals, uint32_t offset, + unsigned threads) { - return knot_zonedb_size(server->zone_db); + uint64_t res = 0; + for (unsigned i = 0; i < threads; i++) { + res += ATOMIC_GET(stats_vals[i][offset]); + } + return res; } -const stats_item_t server_stats[] = { - { "zone-count", { .server_val = server_zone_count } }, - { 0 } -}; - -static uint64_t zone_size(zone_t *zone) +int stats_xdp(stats_dump_ctr_f fcn, stats_dump_ctx_t *ctx) { - return zone->contents != NULL ? zone->contents->size : 0; +#ifdef ENABLE_XDP +#define DUMP(structure, item_name, avg) { \ + params.item_begin = true; \ + params.item = #item_name; \ + params.id = stats[0].if_name; \ + params.value = 0; \ + for (int j = 0; j < i->fd_xdp_count; j++) { \ + params.value += stats[j].structure.item_name; \ + } \ + if (avg) { \ + params.value /= i->fd_xdp_count; \ + } \ + int ret = fcn(¶ms, ctx); \ + if (ret != KNOT_EOK) { \ + return ret; \ + } \ } + stats_dump_params_t params = { .section = "xdp" }; -static uint64_t zone_max_ttl(zone_t *zone) -{ - return zone->contents != NULL ? zone->contents->max_ttl : 0; + if (ctx->section != NULL && strcasecmp(ctx->section, params.section) != 0) { + return KNOT_EOK; + } + + for (const iface_t *i = ctx->server->ifaces; + i != ctx->server->ifaces + ctx->server->n_ifaces; i++) { + if (i->fd_xdp_count == 0) { + continue; + } + knot_xdp_stats_t stats[i->fd_xdp_count]; + for (int j = 0; j < i->fd_xdp_count; j++) { + knot_xdp_socket_stats(i->xdp_sockets[j], &stats[j]); + } + + DUMP(socket, rx_dropped, false); + DUMP(socket, rx_invalid, false); + DUMP(socket, tx_invalid, false); + DUMP(socket, rx_full, false); + DUMP(socket, fq_empty, false); + DUMP(socket, tx_empty, false); + DUMP(rings, tx_busy, true); + DUMP(rings, fq_fill, true); + DUMP(rings, rx_fill, true); + DUMP(rings, tx_fill, true); + DUMP(rings, cq_fill, true); + } +#undef DUMP +#endif + return KNOT_EOK; } -const stats_item_t zone_contents_stats[] = { - { "size", { .zone_val = zone_size } }, - { "max-ttl", { .zone_val = zone_max_ttl } }, - { 0 } -}; +#define DUMP_VAL(params, it, val) { \ + (params).item = (it); \ + (params).value = (val); \ + int ret = fcn(&(params), ctx); \ + if (ret != KNOT_EOK) { \ + return ret; \ + } \ +} -uint64_t stats_get_counter(uint64_t **stats_vals, uint32_t offset, unsigned threads) +int stats_server(stats_dump_ctr_f fcn, stats_dump_ctx_t *ctx) { - uint64_t res = 0; - for (unsigned i = 0; i < threads; i++) { - res += ATOMIC_GET(stats_vals[i][offset]); + stats_dump_params_t params = { .section = "server" }; + + if (ctx->section != NULL && strcasecmp(ctx->section, params.section) != 0) { + return KNOT_EOK; } - return res; + + DUMP_VAL(params, "zone-count", knot_zonedb_size(ctx->server->zone_db)); + + return KNOT_EOK; } -static void dump_common(dump_ctx_t *ctx, knotd_mod_t *mod) +int stats_zone(stats_dump_ctr_f fcn, stats_dump_ctx_t *ctx) { - // Dump zone name. - if (ctx->zone != NULL) { - // Prevent from zone section override. - if (!ctx->zone_emitted) { - ctx->level = 0; - DUMP_STR(ctx->fd, ctx->level++, "zone"); - ctx->zone_emitted = true; - } + knot_dname_txt_storage_t zone; + stats_dump_params_t params = { .section = "zone", .zone = zone }; - if (!ctx->zone_name_emitted) { - ctx->level = 1; - knot_dname_txt_storage_t name; - if (knot_dname_to_str(name, ctx->zone, sizeof(name)) == NULL) { - return; - } - DUMP_STR(ctx->fd, ctx->level++, "\"%s\"", name); - ctx->zone_name_emitted = true; - } + if (ctx->section != NULL && strcasecmp(ctx->section, params.section) != 0) { + return KNOT_EOK; } - if (!ctx->module_emitted) { - DUMP_STR(ctx->fd, ctx->level++, "%s", mod->id->name + 1); - ctx->module_emitted = true; + assert(ctx->zone); + zone_contents_t *contents = ctx->zone->contents; + + if (knot_dname_to_str(zone, ctx->zone->name, sizeof(zone)) == NULL) { + return KNOT_EINVAL; } + + DUMP_VAL(params, "size", contents != NULL ? contents->size : 0); + DUMP_VAL(params, "max-ttl", contents != NULL ? contents->max_ttl : 0); + + return KNOT_EOK; } -static void dump_counter(dump_ctx_t *ctx, knotd_mod_t *mod, mod_ctr_t *ctr) +static int stats_counter(stats_dump_ctr_f fcn, stats_dump_ctx_t *ctx, + stats_dump_params_t *params, knotd_mod_t *mod, mod_ctr_t *ctr) { - uint64_t counter = stats_get_counter(mod->stats_vals, ctr->offset, ctx->threads); - if (counter == 0) { - // Skip empty counter. - return; - } + params->id = NULL; + params->value_pos = 0; - dump_common(ctx, mod); + uint64_t val = stats_get_counter(mod->stats_vals, ctr->offset, ctx->threads); - DUMP_CTR(ctx->fd, ctx->level, "%s", ctr->name, counter); + DUMP_VAL(*params, ctr->name, val); + + return KNOT_EOK; } -static void dump_counters(dump_ctx_t *ctx, knotd_mod_t *mod, mod_ctr_t *ctr) +static int stats_counters(stats_dump_ctr_f fcn, stats_dump_ctx_t *ctx, + stats_dump_params_t *params, knotd_mod_t *mod, mod_ctr_t *ctr) { - bool counter_emitted = false; - for (uint32_t j = 0; j < ctr->count; j++) { - uint64_t counter = stats_get_counter(mod->stats_vals, ctr->offset + j, ctx->threads); - if (counter == 0) { - // Skip empty counter. - continue; - } + char id[64]; + params->id = id; + params->value_pos = 0; + params->item_begin = true; - dump_common(ctx, mod); - - if (!counter_emitted) { - DUMP_STR(ctx->fd, ctx->level, "%s", ctr->name); - counter_emitted = true; - } + for (uint32_t i = 0; i < ctr->count; i++) { + uint64_t val = stats_get_counter(mod->stats_vals, ctr->offset + i, + ctx->threads); if (ctr->idx_to_str != NULL) { - char *str = ctr->idx_to_str(j, ctr->count); - if (str != NULL) { - DUMP_CTR(ctx->fd, ctx->level + 1, "%s", str, counter); - free(str); + char *str = ctr->idx_to_str(i, ctr->count); + if (str == NULL) { + continue; } + (void)snprintf(id, sizeof(id), "%s", str); + free(str); } else { - DUMP_CTR(ctx->fd, ctx->level + 1, "%u", j, counter); + (void)snprintf(id, sizeof(id), "%u", i); } + + DUMP_VAL(*params, ctr->name, val); + params->value_pos++; } + + params->id = NULL; + + return KNOT_EOK; } -static void dump_modules(dump_ctx_t *ctx) +int stats_modules(stats_dump_ctr_f fcn, stats_dump_ctx_t *ctx) { + if (ctx->section != NULL && strncasecmp(ctx->section, "mod-", strlen("mod-")) != 0) { + return KNOT_EOK; + } + + knot_dname_txt_storage_t zone; + stats_dump_params_t params = { 0 }; + knotd_mod_t *mod; WALK_LIST(mod, *ctx->query_modules) { // Skip modules without statistics. @@ -169,39 +197,114 @@ static void dump_modules(dump_ctx_t *ctx) ctx->threads = knotd_mod_threads(mod); } + params.section = mod->id->name + 1; + params.module_begin = true; + if (ctx->zone != NULL && params.zone == NULL) { + params.zone = knot_dname_to_str(zone, ctx->zone->name, + sizeof(zone)); + if (params.zone == NULL) { + return KNOT_EINVAL; + } + } + // Dump module counters. - ctx->module_emitted = false; for (int i = 0; i < mod->stats_count; i++) { mod_ctr_t *ctr = mod->stats_info + i; if (ctr->name == NULL) { // Empty counter. continue; } - if (ctr->count == 1) { - // Simple counter. - dump_counter(ctx, mod, ctr); - } else { - // Array of counters. - dump_counters(ctx, mod, ctr); + int ret = (ctr->count == 1) ? + stats_counter(fcn, ctx, ¶ms, mod, ctr) : + stats_counters(fcn, ctx, ¶ms, mod, ctr); + if (ret != KNOT_EOK) { + return ret; } } - if (ctx->module_emitted) { - ctx->level--; + } + + return KNOT_EOK; +} + +struct { + bool active_dumper; + pthread_t dumper; + uint32_t timer; + server_t *server; +} stats = { 0 }; + +typedef struct { + FILE *fd; + bool section_emitted; + bool zone_section_emitted; + bool zone_emitted; + bool id_emitted; +} dump_ctx_t; + +static int dump_ctr(stats_dump_params_t *params, stats_dump_ctx_t *dump_ctx) +{ + dump_ctx_t *ctx = dump_ctx->ctx; + + if (params->value == 0) { + return KNOT_EOK; + } + + const char *INDENT = " "; + unsigned indent = 0; + + if (params->zone != NULL) { + if (!ctx->zone_section_emitted) { + fprintf(ctx->fd, "zone:\n"); + ctx->zone_section_emitted = true; + } + + if (!ctx->zone_emitted) { + fprintf(ctx->fd, " \"%s\":\n", params->zone); + ctx->zone_emitted = true; } + indent += 2; } + + if (!ctx->section_emitted || params->module_begin) { + fprintf(ctx->fd, "%-.*s%s:\n", indent, INDENT, params->section); + ctx->section_emitted = true; + params->module_begin = false; + } + indent++; + + if (params->id != NULL) { + if (params->item_begin) { + fprintf(ctx->fd, "%-.*s%s:\n", indent, INDENT, params->item); + params->item_begin = false; + } + indent++; + fprintf(ctx->fd, "%-.*s%s: %"PRIu64"\n", indent, INDENT, + params->id, params->value); + } else { + fprintf(ctx->fd, "%-.*s%s: %"PRIu64"\n", indent, INDENT, + params->item, params->value); + } + + return KNOT_EOK; } -static void zone_stats_dump(zone_t *zone, dump_ctx_t *ctx) +static void zone_stats_dump(zone_t *zone, stats_dump_ctx_t *dump_ctx) { if (EMPTY_LIST(zone->query_modules)) { return; } - ctx->query_modules = &zone->query_modules; - ctx->zone = zone->name; - ctx->zone_name_emitted = false; + // Reset per-zone context. + dump_ctx_t *ctx = dump_ctx->ctx; + *ctx = (dump_ctx_t){ + .fd = ctx->fd, + .zone_section_emitted = ctx->zone_section_emitted, + }; + + dump_ctx->zone = zone; + dump_ctx->query_modules = &zone->query_modules; - dump_modules(ctx); + (void)stats_modules(dump_ctr, dump_ctx); } static void dump_to_file(conf_t *conf, FILE *fd, server_t *server) @@ -224,22 +327,28 @@ static void dump_to_file(conf_t *conf, FILE *fd, server_t *server) "identity: %s\n", date, ident); - dump_ctx_t ctx = { - .fd = fd, + dump_ctx_t ctx = { .fd = fd }; + + stats_dump_ctx_t dump_ctx = { + .server = server, .query_modules = conf->query_modules, + .ctx = &ctx, }; - // Dump server statistics. - DUMP_STR(ctx.fd, ctx.level, "server"); - for (const stats_item_t *item = server_stats; item->name != NULL; item++) { - DUMP_CTR(ctx.fd, ctx.level + 1, "%s", item->name, item->server_val(server)); - } + // Dump server counters. + (void)stats_server(dump_ctr, &dump_ctx); + + // Dump XDP counters. + ctx = (dump_ctx_t){ .fd = fd }; + (void)stats_xdp(dump_ctr, &dump_ctx); - // Dump global statistics. - dump_modules(&ctx); + // Dump global module counters. + ctx = (dump_ctx_t){ .fd = fd }; + (void)stats_modules(dump_ctr, &dump_ctx); - // Dump zone statistics. - knot_zonedb_foreach(server->zone_db, zone_stats_dump, &ctx); + // Dump per zone module counters (fixed zone counters not included). + ctx = (dump_ctx_t){ .fd = fd }; + knot_zonedb_foreach(server->zone_db, zone_stats_dump, &dump_ctx); } static void dump_stats(server_t *server) @@ -321,7 +430,6 @@ void stats_reconfigure(conf_t *conf, server_t *server) return; } - // Update server context. stats.server = server; conf_val_t val = conf_get(conf, C_STATS, C_TIMER); diff --git a/src/knot/common/stats.h b/src/knot/common/stats.h index 5cb51ca..4391178 100644 --- a/src/knot/common/stats.h +++ b/src/knot/common/stats.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -20,36 +20,65 @@ #pragma once +#include "contrib/atomic.h" #include "knot/server/server.h" -typedef uint64_t (*stats_server_val_f)(server_t *server); -typedef uint64_t (*stats_zone_val_f)(zone_t *zone); +/*! + * \brief Parameters for a statistic metric dump callback. + */ +typedef struct { + const char *section; + const char *item; + const char *id; + const char *zone; + uint64_t value; + unsigned value_pos; // Counted from 0. + + bool module_begin; // Indication of a new module. + bool item_begin; // Indication of a new item. +} stats_dump_params_t; /*! - * \brief Statistics metrics item. + * \brief Statistic metric context. */ typedef struct { - const char *name; /*!< Metrics name. */ - union { - stats_server_val_f server_val; /*!< Server metrics value getter. */ - stats_zone_val_f zone_val; /*!< Zone metrics value getter. */ - }; -} stats_item_t; + server_t *server; + zone_t *zone; + const list_t *query_modules; + + const char *section; // Optional section specification. + const char *item; // Optional item specification. + bool match; // Indication of non-empty [[section[.item]] selection. + + unsigned threads; // Internal cache for the number of workers. + + void *ctx; +} stats_dump_ctx_t; + +/*! + * \brief Statistic metric dump callback. + */ +typedef int (*stats_dump_ctr_f)(stats_dump_params_t *, stats_dump_ctx_t *); + +/*! + * \brief XDP metrics. + */ +int stats_xdp(stats_dump_ctr_f fcn, stats_dump_ctx_t *ctx); /*! - * \brief Basic server metrics. + * \brief Server metrics. */ -extern const stats_item_t server_stats[]; +int stats_server(stats_dump_ctr_f fcn, stats_dump_ctx_t *ctx); /*! - * \brief Basic zone metrics. + * \brief Zone metrics. */ -extern const stats_item_t zone_contents_stats[]; +int stats_zone(stats_dump_ctr_f fcn, stats_dump_ctx_t *ctx); /*! - * \brief Read out value of single counter summed across threads. + * \brief Modules metrics. */ -uint64_t stats_get_counter(uint64_t **stats_vals, uint32_t offset, unsigned threads); +int stats_modules(stats_dump_ctr_f fcn, stats_dump_ctx_t *ctx); /*! * \brief Reconfigures the statistics facility. diff --git a/src/knot/common/systemd.c b/src/knot/common/systemd.c index 5a72fb4..3f9d9a6 100644 --- a/src/knot/common/systemd.c +++ b/src/knot/common/systemd.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -14,8 +14,6 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. */ -#include <stdarg.h> -#include <stdio.h> #include <stdlib.h> #include "knot/common/systemd.h" @@ -43,12 +41,6 @@ static int systemd_zone_load_timeout(void) } #endif -#ifdef ENABLE_DBUS -#include <systemd/sd-bus.h> - -static sd_bus *_dbus = NULL; -#endif - void systemd_zone_load_timeout_notify(void) { #ifdef ENABLE_SYSTEMD @@ -92,91 +84,3 @@ void systemd_stopping_notify(void) sd_notify(0, "STOPPING=1\nSTATUS="); #endif } - -int systemd_dbus_open(void) -{ -#ifdef ENABLE_DBUS - if (_dbus != NULL) { - return KNOT_EOK; - } - - int ret = sd_bus_open_system(&_dbus); - if (ret < 0) { - return ret; - } - - /* Take a well-known service name so that clients can find us. */ - ret = sd_bus_request_name(_dbus, KNOT_DBUS_NAME, 0); - if (ret < 0) { - systemd_dbus_close(); - return ret; - } - - return KNOT_EOK; -#else - return KNOT_ENOTSUP; -#endif -} - -void systemd_dbus_close(void) -{ -#ifdef ENABLE_DBUS - _dbus = sd_bus_unref(_dbus); -#endif -} - -#define emit_event(event, ...) \ - sd_bus_emit_signal(_dbus, KNOT_DBUS_PATH, KNOT_DBUS_NAME".events", \ - event, __VA_ARGS__) - -void systemd_emit_running(bool up) -{ -#ifdef ENABLE_DBUS - emit_event(up ? KNOT_BUS_EVENT_STARTED : KNOT_BUS_EVENT_STOPPED, ""); -#endif -} - -void systemd_emit_zone_updated(const knot_dname_t *zone_name, uint32_t serial) -{ -#ifdef ENABLE_DBUS - knot_dname_txt_storage_t buff; - char *zone_str = knot_dname_to_str(buff, zone_name, sizeof(buff)); - if (zone_str != NULL) { - emit_event(KNOT_BUS_EVENT_ZONE_UPD, "su", zone_str, serial); - } -#endif -} - -void systemd_emit_keys_updated(const knot_dname_t *zone_name) -{ -#ifdef ENABLE_DBUS - knot_dname_txt_storage_t buff; - char *zone_str = knot_dname_to_str(buff, zone_name, sizeof(buff)); - if (zone_str != NULL) { - emit_event(KNOT_BUS_EVENT_ZONE_KEYS_UPD, "s", zone_str); - } -#endif -} - -void systemd_emit_zone_submission(const knot_dname_t *zone_name, uint16_t keytag, - const char *keyid) -{ -#ifdef ENABLE_DBUS - knot_dname_txt_storage_t buff; - char *zone_str = knot_dname_to_str(buff, zone_name, sizeof(buff)); - if (zone_str != NULL) { - emit_event(KNOT_BUS_EVENT_ZONE_KSK_SUBM, "sqs", zone_str, keytag, keyid); - } -#endif -} - -void systemd_emit_zone_invalid(const knot_dname_t *zone_name) -{ -#ifdef ENABLE_DBUS - knot_dname_txt_storage_t buff; - char *zone_str = knot_dname_to_str(buff, zone_name, sizeof(buff)); - if (zone_str != NULL) { - emit_event(KNOT_BUS_EVENT_ZONE_INVALID, "s", zone_str); - } -#endif -} diff --git a/src/knot/common/systemd.h b/src/knot/common/systemd.h index c6fe260..2038e94 100644 --- a/src/knot/common/systemd.h +++ b/src/knot/common/systemd.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -20,18 +20,6 @@ #pragma once -#include "libknot/libknot.h" - -#define KNOT_DBUS_NAME "cz.nic.knotd" -#define KNOT_DBUS_PATH "/cz/nic/knotd" - -#define KNOT_BUS_EVENT_STARTED "started" -#define KNOT_BUS_EVENT_STOPPED "stopped" -#define KNOT_BUS_EVENT_ZONE_UPD "zone_updated" -#define KNOT_BUS_EVENT_ZONE_KEYS_UPD "keys_updated" -#define KNOT_BUS_EVENT_ZONE_KSK_SUBM "zone_ksk_submission" -#define KNOT_BUS_EVENT_ZONE_INVALID "zone_dnssec_invalid" - /*! * \brief Notify systemd about zone loading start. */ @@ -59,55 +47,3 @@ void systemd_reloading_notify(void); * \brief Notify systemd about service is stopping. */ void systemd_stopping_notify(void); - -/*! - * \brief Creates unique D-Bus sender reference (common for whole process). - * - * \retval KNOT_EOK on successful create of reference. - * \retval Negative value on error. - */ -int systemd_dbus_open(void); - -/*! - * \brief Closes D-Bus. - */ -void systemd_dbus_close(void); - -/*! - * \brief Emit event signal for started daemon. - * - * \param up Indication if the server has been started. - */ -void systemd_emit_running(bool up); - -/*! - * \brief Emit event signal for updated zones. - * - * \param zone_name Zone name. - * \param serial Current zone SOA serial. - */ -void systemd_emit_zone_updated(const knot_dname_t *zone_name, uint32_t serial); - -/*! - * \brief Emit event signal for updated DNSSEC key set. - * - * \param zone_name Zone name. - */ -void systemd_emit_keys_updated(const knot_dname_t *zone_name); - -/*! - * \brief Emit event signal for KSK submission. - * - * \param zone_name Zone name. - * \param keytag Keytag of the ready key. - * \param keyid KASP id of the ready key. - */ -void systemd_emit_zone_submission(const knot_dname_t *zone_name, uint16_t keytag, - const char *keyid); - -/*! - * \brief Emit event signal for failed DNSSEC validation. - * - * \param zone_name Zone name. - */ -void systemd_emit_zone_invalid(const knot_dname_t *zone_name); diff --git a/src/knot/conf/base.c b/src/knot/conf/base.c index 51caf10..4683171 100644 --- a/src/knot/conf/base.c +++ b/src/knot/conf/base.c @@ -130,6 +130,9 @@ static void init_cache( static bool running_xdp_tcp; static uint16_t running_xdp_quic; static bool running_route_check; + static uint16_t running_ring_size; + static uint16_t running_busypoll_budget; + static uint16_t running_busypoll_timeout; static size_t running_udp_threads; static size_t running_tcp_threads; static size_t running_xdp_threads; @@ -148,6 +151,9 @@ static void init_cache( running_xdp_quic = conf_get_int(conf, C_XDP, C_QUIC_PORT); } running_route_check = conf_get_bool(conf, C_XDP, C_ROUTE_CHECK); + running_ring_size = conf_get_int(conf, C_XDP, C_RING_SIZE); + running_busypoll_budget = conf_get_int(conf, C_XDP, C_BUSYPOLL_BUDGET); + running_busypoll_timeout = conf_get_int(conf, C_XDP, C_BUSYPOLL_TIMEOUT); running_udp_threads = conf_udp_threads(conf); running_tcp_threads = conf_tcp_threads(conf); running_xdp_threads = conf_xdp_threads(conf); @@ -235,6 +241,12 @@ static void init_cache( conf->cache.xdp_route_check = running_route_check; + conf->cache.xdp_ring_size = running_ring_size; + + conf->cache.xdp_busypoll_budget = running_busypoll_budget; + + conf->cache.xdp_busypoll_timeout = running_busypoll_timeout; + val = conf_get(conf, C_CTL, C_TIMEOUT); conf->cache.ctl_timeout = conf_int(&val) * 1000; /* infinite_adjust() call isn't needed, 0 is adjusted later anyway. */ @@ -335,9 +347,10 @@ int conf_new( ret = out->api->init(&out->db, NULL, &lmdb_opts); // Remove the database to ensure it is temporary. - if (!remove_path(lmdb_opts.path)) { - CONF_LOG(LOG_WARNING, "failed to purge temporary directory '%s'", - lmdb_opts.path); + int ret2 = remove_path(lmdb_opts.path, false); + if (ret2 != KNOT_EOK) { + CONF_LOG(LOG_WARNING, "failed to purge temporary directory '%s' (%s)", + lmdb_opts.path, knot_strerror(ret2)); } } else { // Set the specified database. diff --git a/src/knot/conf/base.h b/src/knot/conf/base.h index 5c77cac..1ac5ef5 100644 --- a/src/knot/conf/base.h +++ b/src/knot/conf/base.h @@ -165,6 +165,9 @@ typedef struct { const char *srv_version; uint32_t srv_quic_idle_close; uint16_t xdp_quic; + uint16_t xdp_ring_size; + uint16_t xdp_busypoll_budget; + uint16_t xdp_busypoll_timeout; int ctl_timeout; bool xdp_udp; bool xdp_tcp; diff --git a/src/knot/conf/conf.c b/src/knot/conf/conf.c index 55ee971..5e9ed83 100644 --- a/src/knot/conf/conf.c +++ b/src/knot/conf/conf.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -606,8 +606,9 @@ void conf_mix_iter_next( } } -int64_t conf_int( - conf_val_t *val) +int64_t conf_int_alt( + conf_val_t *val, + bool alternative) { assert(val != NULL && val->item != NULL); assert(val->item->type == YP_TINT || @@ -618,7 +619,7 @@ int64_t conf_int( conf_val(val); return yp_int(val->data); } else { - return val->item->var.i.dflt; + return alternative ? val->item->var.i.dflt_alt : val->item->var.i.dflt; } } @@ -1063,7 +1064,7 @@ static int str_label( size_t index = labels - right_index - 1; // Create a dname from the single label. - size_t prefix_len = knot_dname_prefixlen(zone, index, NULL); + size_t prefix_len = knot_dname_prefixlen(zone, index); size_t label_len = *(zone + prefix_len); memcpy(label, zone + prefix_len, 1 + label_len); label[1 + label_len] = '\0'; @@ -1379,6 +1380,8 @@ conf_remote_t conf_remote_txn( conf_val_t val = conf_id_get_txn(conf, txn, C_RMT, C_QUIC, id); out.quic = conf_bool(&val); + val = conf_id_get_txn(conf, txn, C_RMT, C_TLS, id); + out.tls = conf_bool(&val); conf_val_t rundir_val = conf_get_txn(conf, txn, C_SRV, C_RUNDIR); char *rundir = conf_abs_path(&rundir_val, NULL); @@ -1398,7 +1401,7 @@ conf_remote_t conf_remote_txn( conf_val_next(&val); } // Index overflow causes empty socket. - out.addr = conf_addr_alt(&val, rundir, out.quic); + out.addr = conf_addr_alt(&val, rundir, out.quic || out.tls); // Get outgoing address if family matches (optional). uint16_t via_pos = 0; diff --git a/src/knot/conf/conf.h b/src/knot/conf/conf.h index 562722d..f79a284 100644 --- a/src/knot/conf/conf.h +++ b/src/knot/conf/conf.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -44,6 +44,8 @@ typedef struct { struct sockaddr_storage via; /*! QUIC context. */ bool quic; + /*! TLS context. */ + bool tls; /*! TSIG key. */ knot_tsig_key_t key; /*! Suppress sending NOTIFY after zone transfer from this master. */ @@ -469,13 +471,20 @@ void conf_mix_iter_next( /*! * Gets the numeric value of the item. * - * \param[in] val Item value. + * \param[in] val Item value. + * \param[in] alternative Use alternative default value. * * \return Integer. */ -int64_t conf_int( - conf_val_t *val +int64_t conf_int_alt( + conf_val_t *val, + bool alternative ); +inline static int64_t conf_int( + conf_val_t *val) +{ + return conf_int_alt(val, false); +} /*! * Gets the boolean value of the item. diff --git a/src/knot/conf/schema.c b/src/knot/conf/schema.c index 7b30a2f..fd55fc8 100644 --- a/src/knot/conf/schema.c +++ b/src/knot/conf/schema.c @@ -64,9 +64,7 @@ static const knot_lookup_t dnssec_key_algs[] = { { DNSSEC_KEY_ALGORITHM_RSA_SHA512, "rsasha512" }, { DNSSEC_KEY_ALGORITHM_ECDSA_P256_SHA256, "ecdsap256sha256" }, { DNSSEC_KEY_ALGORITHM_ECDSA_P384_SHA384, "ecdsap384sha384" }, -#ifdef HAVE_ED25519 { DNSSEC_KEY_ALGORITHM_ED25519, "ed25519" }, -#endif #ifdef HAVE_ED448 { DNSSEC_KEY_ALGORITHM_ED448, "ed448" }, #endif @@ -249,15 +247,8 @@ static const yp_item_t desc_server[] = { { C_DBUS_INIT_DELAY, YP_TINT, YP_VINT = { 0, INT32_MAX, 1, YP_STIME } }, { C_LISTEN, YP_TADDR, YP_VADDR = { 53 }, YP_FMULTI, { check_listen } }, { C_LISTEN_QUIC, YP_TADDR, YP_VADDR = { 853 }, YP_FMULTI, { check_listen } }, + { C_LISTEN_TLS, YP_TADDR, YP_VADDR = { 853 }, YP_FMULTI, { check_listen } }, { C_COMMENT, YP_TSTR, YP_VNONE }, - // Legacy items. - { C_LISTEN_XDP, YP_TADDR, YP_VADDR = { 0 }, YP_FMULTI, { legacy_item } }, - { C_MAX_TCP_CLIENTS, YP_TINT, YP_VINT = { 0, INT32_MAX, 0 }, YP_FNONE, { legacy_item } }, - { C_TCP_HSHAKE_TIMEOUT, YP_TINT, YP_VINT = { 0, INT32_MAX, 0, YP_STIME }, YP_FNONE, { legacy_item } }, - { C_TCP_REPLY_TIMEOUT, YP_TINT, YP_VINT = { 0, INT32_MAX, 0, YP_STIME }, YP_FNONE, { legacy_item } }, - { C_MAX_UDP_PAYLOAD, YP_TINT, YP_VINT = { 0, INT32_MAX, 0, YP_SSIZE }, YP_FNONE, { legacy_item } }, - { C_MAX_IPV4_UDP_PAYLOAD, YP_TINT, YP_VINT = { 0, INT32_MAX, 0, YP_SSIZE }, YP_FNONE, { legacy_item } }, - { C_MAX_IPV6_UDP_PAYLOAD, YP_TINT, YP_VINT = { 0, INT32_MAX, 0, YP_SSIZE }, YP_FNONE, { legacy_item } }, { NULL } }; @@ -274,10 +265,10 @@ static const yp_item_t desc_xdp[] = { { C_TCP_IDLE_RESET, YP_TINT, YP_VINT = { 1, INT32_MAX, 20, YP_STIME } }, { C_TCP_RESEND, YP_TINT, YP_VINT = { 1, INT32_MAX, 5, YP_STIME } }, { C_ROUTE_CHECK, YP_TBOOL, YP_VNONE }, - { C_EXTRA_FRAMES, YP_TBOOL, YP_VNONE }, + { C_RING_SIZE, YP_TINT, YP_VINT = { 4, 32768, 2048 } }, + { C_BUSYPOLL_BUDGET, YP_TINT, YP_VINT = { 0, UINT16_MAX, 0 } }, + { C_BUSYPOLL_TIMEOUT, YP_TINT, YP_VINT = { 1, UINT16_MAX, 20 } }, { C_COMMENT, YP_TSTR, YP_VNONE }, - // Legacy items. - { C_QUIC_LOG, YP_TBOOL, YP_VNONE, YP_FNONE, { legacy_item } }, { NULL } }; @@ -350,6 +341,7 @@ static const yp_item_t desc_remote[] = { { C_ADDR, YP_TADDR, YP_VADDR = { 53, 853 }, YP_FMULTI }, { C_VIA, YP_TADDR, YP_VNONE, YP_FMULTI }, { C_QUIC, YP_TBOOL, YP_VNONE }, + { C_TLS, YP_TBOOL, YP_VNONE }, { C_KEY, YP_TREF, YP_VREF = { C_KEY }, YP_FNONE, { check_ref } }, { C_CERT_KEY, YP_TB64, YP_VNONE, YP_FMULTI, { check_cert_pin } }, { C_BLOCK_NOTIFY_XFR, YP_TBOOL, YP_VNONE }, @@ -432,7 +424,7 @@ static const yp_item_t desc_policy[] = { CONF_IO_FRLD_ZONES }, { C_RRSIG_REFRESH, YP_TINT, YP_VINT = { 1, INT32_MAX, YP_NIL, YP_STIME }, CONF_IO_FRLD_ZONES }, - { C_RRSIG_PREREFRESH, YP_TINT, YP_VINT = { 0, INT32_MAX, HOURS(1), YP_STIME }, + { C_RRSIG_PREREFRESH, YP_TINT, YP_VINT = { 0, INT32_MAX, HOURS(1), YP_STIME, DAYS(1) }, CONF_IO_FRLD_ZONES }, { C_REPRO_SIGNING, YP_TBOOL, YP_VNONE, CONF_IO_FRLD_ZONES }, { C_NSEC3, YP_TBOOL, YP_VNONE, CONF_IO_FRLD_ZONES }, @@ -506,27 +498,12 @@ static const yp_item_t desc_policy[] = { { C_MODULE, YP_TDATA, YP_VDATA = { 0, NULL, mod_id_to_bin, mod_id_to_txt }, \ YP_FMULTI | FLAGS, { check_modref } }, \ { C_COMMENT, YP_TSTR, YP_VNONE }, \ - /* Legacy items.*/ \ - { C_DISABLE_ANY, YP_TBOOL, YP_VNONE, YP_FNONE, { legacy_item } }, \ - { C_MAX_ZONE_SIZE, YP_TINT, YP_VINT = { 0, SSIZE_MAX, 0, YP_SSIZE }, YP_FNONE, { legacy_item } }, \ - { C_MAX_JOURNAL_USAGE, YP_TINT, YP_VINT = { 0, SSIZE_MAX, 0, YP_SSIZE }, YP_FNONE, { legacy_item } }, \ - { C_MAX_JOURNAL_DEPTH, YP_TINT, YP_VINT = { 0, SSIZE_MAX, 0 }, YP_FNONE, { legacy_item } }, \ - { C_MAX_REFRESH_INTERVAL,YP_TINT, YP_VINT = { 0, SSIZE_MAX, 0, YP_STIME }, YP_FNONE, { legacy_item } }, \ - { C_MIN_REFRESH_INTERVAL,YP_TINT, YP_VINT = { 0, SSIZE_MAX, 0, YP_STIME }, YP_FNONE, { legacy_item } }, \ static const yp_item_t desc_template[] = { { C_ID, YP_TSTR, YP_VNONE, CONF_IO_FREF }, { C_GLOBAL_MODULE, YP_TDATA, YP_VDATA = { 0, NULL, mod_id_to_bin, mod_id_to_txt }, YP_FMULTI | CONF_IO_FRLD_MOD, { check_modref } }, ZONE_ITEMS(CONF_IO_FRLD_ZONES) - // Legacy items. - { C_TIMER_DB, YP_TSTR, YP_VSTR = { "" }, YP_FNONE, { legacy_item } }, - { C_MAX_TIMER_DB_SIZE, YP_TINT, YP_VINT = { 0, SSIZE_MAX, 0, YP_SSIZE }, YP_FNONE, { legacy_item } }, - { C_JOURNAL_DB, YP_TSTR, YP_VSTR = { "" }, YP_FNONE, { legacy_item } }, - { C_JOURNAL_DB_MODE, YP_TOPT, YP_VOPT = { journal_modes, 0 }, YP_FNONE, { legacy_item } }, - { C_MAX_JOURNAL_DB_SIZE, YP_TINT, YP_VINT = { 0, SSIZE_MAX, 0, YP_SSIZE }, YP_FNONE, { legacy_item } }, - { C_KASP_DB, YP_TSTR, YP_VSTR = { "" }, YP_FNONE, { legacy_item } }, - { C_MAX_KASP_DB_SIZE, YP_TINT, YP_VINT = { 0, SSIZE_MAX, 0, YP_SSIZE }, YP_FNONE, { legacy_item } }, { NULL } }; diff --git a/src/knot/conf/schema.h b/src/knot/conf/schema.h index dc5a04e..d2966e6 100644 --- a/src/knot/conf/schema.h +++ b/src/knot/conf/schema.h @@ -33,6 +33,8 @@ #define C_BACKLOG "\x07""backlog" #define C_BG_WORKERS "\x12""background-workers" #define C_BLOCK_NOTIFY_XFR "\x1B""block-notify-after-transfer" +#define C_BUSYPOLL_BUDGET "\x0F""busypoll-budget" +#define C_BUSYPOLL_TIMEOUT "\x10""busypoll-timeout" #define C_CATALOG_DB "\x0A""catalog-db" #define C_CATALOG_DB_MAX_SIZE "\x13""catalog-db-max-size" #define C_CATALOG_GROUP "\x0D""catalog-group" @@ -65,7 +67,6 @@ #define C_ECS "\x12""edns-client-subnet" #define C_EXPIRE_MAX_INTERVAL "\x13""expire-max-interval" #define C_EXPIRE_MIN_INTERVAL "\x13""expire-min-interval" -#define C_EXTRA_FRAMES "\x0C""extra-frames" #define C_FILE "\x04""file" #define C_GLOBAL_MODULE "\x0D""global-module" #define C_ID "\x02""id" @@ -94,6 +95,7 @@ #define C_KSK_SIZE "\x08""ksk-size" #define C_LISTEN "\x06""listen" #define C_LISTEN_QUIC "\x0B""listen-quic" +#define C_LISTEN_TLS "\x0A""listen-tls" #define C_LOG "\x03""log" #define C_MANUAL "\x06""manual" #define C_MASTER "\x06""master" @@ -117,7 +119,6 @@ #define C_PROXY_ALLOWLIST "\x0F""proxy-allowlist" #define C_QUIC "\x04""quic" #define C_QUIC_IDLE_CLOSE "\x17""quic-idle-close-timeout" -#define C_QUIC_LOG "\x08""quic-log" #define C_QUIC_MAX_CLIENTS "\x10""quic-max-clients" #define C_QUIC_OUTBUF_MAX_SIZE "\x14""quic-outbuf-max-size" #define C_QUIC_PORT "\x09""quic-port" @@ -127,6 +128,7 @@ #define C_RETRY_MAX_INTERVAL "\x12""retry-max-interval" #define C_RETRY_MIN_INTERVAL "\x12""retry-min-interval" #define C_REVERSE_GEN "\x10""reverse-generate" +#define C_RING_SIZE "\x09""ring-size" #define C_RMT "\x06""remote" #define C_RMTS "\x07""remotes" #define C_RMT_POOL_LIMIT "\x11""remote-pool-limit" @@ -167,6 +169,7 @@ #define C_TIMER "\x05""timer" #define C_TIMER_DB "\x08""timer-db" #define C_TIMER_DB_MAX_SIZE "\x11""timer-db-max-size" +#define C_TLS "\x03""tls" #define C_TPL "\x08""template" #define C_UDP "\x03""udp" #define C_UDP_MAX_PAYLOAD "\x0F""udp-max-payload" @@ -192,24 +195,6 @@ #define C_ZSK_LIFETIME "\x0C""zsk-lifetime" #define C_ZSK_SIZE "\x08""zsk-size" -// Legacy items. -#define C_DISABLE_ANY "\x0B""disable-any" -#define C_LISTEN_XDP "\x0A""listen-xdp" -#define C_MAX_TIMER_DB_SIZE "\x11""max-timer-db-size" -#define C_MAX_JOURNAL_DB_SIZE "\x13""max-journal-db-size" -#define C_MAX_KASP_DB_SIZE "\x10""max-kasp-db-size" -#define C_TCP_HSHAKE_TIMEOUT "\x15""tcp-handshake-timeout" -#define C_TCP_REPLY_TIMEOUT "\x11""tcp-reply-timeout" -#define C_MAX_TCP_CLIENTS "\x0F""max-tcp-clients" -#define C_MAX_UDP_PAYLOAD "\x0F""max-udp-payload" -#define C_MAX_IPV4_UDP_PAYLOAD "\x14""max-ipv4-udp-payload" -#define C_MAX_IPV6_UDP_PAYLOAD "\x14""max-ipv6-udp-payload" -#define C_MAX_ZONE_SIZE "\x0D""max-zone-size" -#define C_MAX_REFRESH_INTERVAL "\x14""max-refresh-interval" -#define C_MIN_REFRESH_INTERVAL "\x14""min-refresh-interval" -#define C_MAX_JOURNAL_DEPTH "\x11""max-journal-depth" -#define C_MAX_JOURNAL_USAGE "\x11""max-journal-usage" - enum { KEYSTORE_BACKEND_PEM = 1, KEYSTORE_BACKEND_PKCS11 = 2, diff --git a/src/knot/conf/tools.c b/src/knot/conf/tools.c index e232fba..1ea8446 100644 --- a/src/knot/conf/tools.c +++ b/src/knot/conf/tools.c @@ -43,9 +43,7 @@ #include "knot/updates/acl.h" #include "knot/zone/serial.h" #include "libknot/errcode.h" -#ifdef ENABLE_QUIC -#include "libknot/quic/quic.h" -#endif // ENABLE_QUIC +#include "libknot/quic/tls_common.h" #include "libknot/yparser/yptrafo.h" #include "libknot/xdp.h" #include "contrib/files.h" @@ -345,15 +343,13 @@ int check_xdp_listen( int check_cert_pin( knotd_conf_check_args_t *args) { -#ifdef ENABLE_QUIC - if (args->data_len != sizeof(uint16_t) + KNOT_QUIC_PIN_LEN) { + if (args->data_len != sizeof(uint16_t) + KNOT_TLS_PIN_LEN) { (void)snprintf(check_str, sizeof(check_str), "invalid certificate pin, expected base64-encoded " - "%u bytes", KNOT_QUIC_PIN_LEN); + "%u bytes", KNOT_TLS_PIN_LEN); args->err_str = check_str; return KNOT_EINVAL; } -#endif // ENABLE_QUIC return KNOT_EOK; } @@ -551,7 +547,6 @@ static void check_mtu(knotd_conf_check_args_t *args, conf_val_t *xdp_listen) #endif } -#ifdef ENABLE_QUIC static bool listen_hit(const struct sockaddr_storage *ss1, const struct sockaddr_storage *ss2) { @@ -562,7 +557,33 @@ static bool listen_hit(const struct sockaddr_storage *ss1, return sockaddr_cmp(ss1, ss2, false) == 0; } } -#endif // ENABLE_QUIC + +static bool listen_overlaps( + knotd_conf_check_args_t *args, + conf_val_t *chk_listen, + size_t chk_listen_count) +{ + conf_val_t listen_val = conf_get_txn(args->extra->conf, args->extra->txn, + C_SRV, C_LISTEN); + size_t listen_count = conf_val_count(&listen_val); + + for (size_t i = 0; listen_count > 0 && i < chk_listen_count; i++) { + struct sockaddr_storage chk_addr = conf_addr(chk_listen, NULL); + + for (size_t j = 0; j < listen_count; j++) { + struct sockaddr_storage listen_addr = conf_addr(&listen_val, NULL); + if (listen_hit(&chk_addr, &listen_addr)) { + return true; + } + conf_val_next(&listen_val); + } + + conf_val(&listen_val); + conf_val_next(chk_listen); + } + + return false; +} int check_server( knotd_conf_check_args_t *args) @@ -576,30 +597,26 @@ int check_server( return KNOT_EINVAL; } + conf_val_t listls_val = conf_get_txn(args->extra->conf, args->extra->txn, + C_SRV, C_LISTEN_TLS); + size_t listls_count = conf_val_count(&listls_val); + if (listls_count > 0) { + if (listen_overlaps(args, &listls_val, listls_count)) { + args->err_str = "TLS listen address/port overlaps " + "with TCP listen address/port"; + return KNOT_EINVAL; + } + } + conf_val_t liquic_val = conf_get_txn(args->extra->conf, args->extra->txn, C_SRV, C_LISTEN_QUIC); size_t liquic_count = conf_val_count(&liquic_val); if (liquic_count > 0) { #ifdef ENABLE_QUIC - conf_val_t listen_val = conf_get_txn(args->extra->conf, args->extra->txn, - C_SRV, C_LISTEN); - size_t listen_count = conf_val_count(&listen_val); - - for (size_t i = 0; listen_count > 0 && i < liquic_count; i++) { - struct sockaddr_storage liquic_addr = conf_addr(&liquic_val, NULL); - - for (size_t j = 0; j < listen_count; j++) { - struct sockaddr_storage listen_addr = conf_addr(&listen_val, NULL); - if (listen_hit(&liquic_addr, &listen_addr)) { - args->err_str = "QUIC listen address/port overlaps " - "with UDP listen address/port"; - return KNOT_EINVAL; - } - conf_val_next(&listen_val); - } - - conf_val(&listen_val); - conf_val_next(&liquic_val); + if (listen_overlaps(args, &liquic_val, liquic_count)) { + args->err_str = "QUIC listen address/port overlaps " + "with UDP listen address/port"; + return KNOT_EINVAL; } #else args->err_str = "QUIC processing not available"; @@ -713,10 +730,6 @@ int check_policy( C_NSEC3_ITER, args->id, args->id_len); unsigned algorithm = conf_opt(&alg); - if (algorithm < DNSSEC_KEY_ALGORITHM_RSA_SHA256) { - CONF_LOG(LOG_NOTICE, "algorithm %u is deprecated and shouldn't be used for DNSSEC signing", - algorithm); - } int64_t ksk_size = conf_int(&ksk); if (ksk_size != YP_NIL && !dnssec_algorithm_key_size_check(algorithm, ksk_size)) { @@ -779,14 +792,6 @@ int check_policy( return KNOT_EINVAL; } -#ifndef HAVE_GNUTLS_REPRODUCIBLE - conf_val_t repro_sign = conf_rawid_get_txn(args->extra->conf, args->extra->txn, C_POLICY, - C_REPRO_SIGNING, args->id, args->id_len); - if (conf_bool(&repro_sign)) { - CONF_LOG(LOG_WARNING, "reproducible signing not available, signing normally"); - } -#endif - if (conf_bool(&nsec3)) { uint16_t iters = conf_int(&nsec3_iters); if (iters > 0) { @@ -880,12 +885,18 @@ int check_remote( return KNOT_EINVAL; } + conf_val_t tls = conf_rawid_get_txn(args->extra->conf, args->extra->txn, C_RMT, + C_TLS, args->id, args->id_len); conf_val_t quic = conf_rawid_get_txn(args->extra->conf, args->extra->txn, C_RMT, C_QUIC, args->id, args->id_len); if (quic.code == KNOT_EOK) { #ifdef ENABLE_QUIC - (void)0; + if (conf_bool(&quic) && conf_bool(&tls)) { + args->err_str = "remote can't use both QUIC and TLS"; + return KNOT_EINVAL; + } #else + (void)tls; args->err_str = "QUIC not available"; return KNOT_EINVAL; #endif diff --git a/src/knot/ctl/commands.c b/src/knot/ctl/commands.c index 7febce1..56e1d67 100644 --- a/src/knot/ctl/commands.c +++ b/src/knot/ctl/commands.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -17,12 +17,14 @@ #include <string.h> #include <unistd.h> #include <sys/time.h> +#include <time.h> #include <urcu.h> #include "knot/common/log.h" #include "knot/common/stats.h" #include "knot/conf/confio.h" #include "knot/ctl/commands.h" +#include "knot/ctl/process.h" #include "knot/dnssec/key-events.h" #include "knot/events/events.h" #include "knot/events/handlers.h" @@ -36,6 +38,7 @@ #include "knot/zone/zonefile.h" #include "libknot/libknot.h" #include "libknot/yparser/yptrafo.h" +#include "contrib/atomic.h" #include "contrib/files.h" #include "contrib/string.h" #include "contrib/strtonum.h" @@ -68,7 +71,7 @@ static struct { sizeof(((send_ctx_t *)0)->ttl) + sizeof(((send_ctx_t *)0)->type) + sizeof(((send_ctx_t *)0)->rdata)]; -} ctl_globals; +} ctl_globals[CTL_MAX_CONCURRENT + 1]; static bool allow_blocking_while_ctl_txn(zone_event_type_t event) { @@ -645,47 +648,49 @@ static int zone_backup_cmd(zone_t *zone, ctl_args_t *args) return KNOT_EOK; } + int ret = KNOT_EOK; + pthread_mutex_lock(&zone->cu_lock); if (zone->backup_ctx != NULL) { log_zone_warning(zone->name, "backup or restore already in progress, skipping zone"); ctx->failed = true; - return KNOT_EPROGRESS; + ret = KNOT_EPROGRESS; } - if (ctx->restore_mode && zone->control_update != NULL) { + if (ctx->restore_mode && zone->control_update != NULL && ret == KNOT_EOK) { log_zone_warning(zone->name, "restoring backup not possible due to open control transaction"); ctx->failed = true; - return KNOT_TXN_EEXISTS; + ret = KNOT_TXN_EEXISTS; + } + + if (ret == KNOT_EOK) { + zone->backup_ctx = ctx; } + pthread_mutex_unlock(&zone->cu_lock); ctx->zone_count++; - int ret; - if (!ctx->backup_global) { + if (!ctx->backup_global && ret == KNOT_EOK) { ret = global_backup(ctx, zone_catalog(zone), zone->name); - if (ret != KNOT_EOK) { - return ret; - } } - if (ctx->backup_params & BACKUP_PARAM_KEYSONLY) { + bool finish = false; + if ((ctx->backup_params & BACKUP_PARAM_KEYSONLY) && ret == KNOT_EOK) { ret = zone_backup_keysonly(ctx, conf(), zone); - if (ret != KNOT_EOK) { - return ret; - } - if (ctx->restore_mode) { + if (ctx->restore_mode && ret == KNOT_EOK) { ret = zone_keys_load(zone, args); - if (ret != KNOT_EOK) { - return ret; - } } if (!(ctx->backup_params & BACKUP_PARAM_EVENT)) { - return ret; + finish = true; } } - zone->backup_ctx = ctx; + if (ret != KNOT_EOK || finish) { + zone->backup_ctx = NULL; + return ret; + } + pthread_mutex_lock(&ctx->readers_mutex); ctx->readers++; pthread_mutex_unlock(&ctx->readers_mutex); @@ -720,7 +725,7 @@ static int zones_apply_backup(ctl_args_t *args, bool restore_mode) zone_backup_ctx_t *ctx = latest_backup_ctx(args); /* QUIC - server key and cert backup. */ - ret = backup_quic(ctx, args->server->quic_active); + ret = backup_quic(ctx, args->server->quic_active || args->server->tls_active); if (ret != KNOT_EOK) { log_ctl_error("control, QUIC %s error (%s)", restore_mode ? "restore" : "backup", @@ -761,6 +766,11 @@ static int zone_sign(zone_t *zone, _unused_ ctl_args_t *args) return schedule_trigger(zone, args, ZONE_EVENT_DNSSEC, true); } +static int zone_validate(zone_t *zone, _unused_ ctl_args_t *args) +{ + return schedule_trigger(zone, args, ZONE_EVENT_VALIDATE, true); +} + static int zone_keys_load(zone_t *zone, _unused_ ctl_args_t *args) { conf_val_t val = conf_zone_get(conf(), C_DNSSEC_SIGNING, zone->name); @@ -811,8 +821,8 @@ static int zone_ksk_sbm_confirm(zone_t *zone, _unused_ ctl_args_t *args) conf_val_t val = conf_zone_get(conf(), C_DNSSEC_SIGNING, zone->name); if (ret == KNOT_EOK && conf_bool(&val)) { - // NOT zone_events_schedule_user(), intentionally! - ret = schedule_trigger(zone, args, ZONE_EVENT_DNSSEC, false); + // NOT zone_events_schedule_user() or schedule_trigger(), intentionally! + zone_events_schedule_now(zone, ZONE_EVENT_DNSSEC); } return ret; @@ -846,17 +856,23 @@ static int zone_xfr_thaw(zone_t *zone, _unused_ ctl_args_t *args) return KNOT_EOK; } -static int zone_txn_begin(zone_t *zone, _unused_ ctl_args_t *args) +static int zone_txn_begin_l(zone_t *zone, _unused_ ctl_args_t *args) { - if (zone->control_update != NULL) { + if (zone->control_update != NULL || conf()->io.txn != NULL) { return KNOT_TXN_EEXISTS; } - if (zone->backup_ctx != NULL && zone->backup_ctx->restore_mode) { + struct zone_backup_ctx *backup_ctx = zone->backup_ctx; + if (backup_ctx != NULL && backup_ctx->restore_mode) { log_zone_warning(zone->name, "zone restore pending, try opening control transaction later"); return KNOT_EAGAIN; } + if (zone->events.running && zone->events.type >= 0 && zone->events.blocking[zone->events.type] != NULL) { + log_zone_warning(zone->name, "some blocking event running, try opening control transaction later"); + return KNOT_EAGAIN; + } + zone->control_update = malloc(sizeof(zone_update_t)); if (zone->control_update == NULL) { return KNOT_ENOMEM; @@ -872,7 +888,15 @@ static int zone_txn_begin(zone_t *zone, _unused_ ctl_args_t *args) return ret; } -static int zone_txn_commit(zone_t *zone, _unused_ ctl_args_t *args) +static int zone_txn_begin(zone_t *zone, ctl_args_t *args) +{ + pthread_mutex_lock(&zone->cu_lock); + int ret = zone_txn_begin_l(zone, args); + pthread_mutex_unlock(&zone->cu_lock); + return ret; +} + +static int zone_txn_commit_l(zone_t *zone, _unused_ ctl_args_t *args) { if (zone->control_update == NULL) { args->suppress = true; @@ -934,15 +958,26 @@ static int zone_txn_commit(zone_t *zone, _unused_ ctl_args_t *args) return KNOT_EOK; } +static int zone_txn_commit(zone_t *zone, ctl_args_t *args) +{ + pthread_mutex_lock(&zone->cu_lock); + int ret = zone_txn_commit_l(zone, args); + pthread_mutex_unlock(&zone->cu_lock); + return ret; +} + static int zone_txn_abort(zone_t *zone, _unused_ ctl_args_t *args) { + pthread_mutex_lock(&zone->cu_lock); if (zone->control_update == NULL) { args->suppress = true; + pthread_mutex_unlock(&zone->cu_lock); return KNOT_TXN_ENOTEXISTS; } zone_control_clear(zone); + pthread_mutex_unlock(&zone->cu_lock); return KNOT_EOK; } @@ -1089,7 +1124,7 @@ static int get_owner(uint8_t *out, size_t out_len, knot_dname_t *origin, static int zone_read(zone_t *zone, ctl_args_t *args) { - send_ctx_t *ctx = &ctl_globals.send_ctx; + send_ctx_t *ctx = &ctl_globals[args->thread_idx].send_ctx; int ret = init_send_ctx(ctx, zone->name, args); if (ret != KNOT_EOK) { return ret; @@ -1131,7 +1166,7 @@ static int zone_flag_txn_get(zone_t *zone, ctl_args_t *args, const char *flag) return KNOT_TXN_ENOTEXISTS; } - send_ctx_t *ctx = &ctl_globals.send_ctx; + send_ctx_t *ctx = &ctl_globals[args->thread_idx].send_ctx; int ret = init_send_ctx(ctx, zone->name, args); if (ret != KNOT_EOK) { return ret; @@ -1170,7 +1205,10 @@ static int zone_flag_txn_get(zone_t *zone, ctl_args_t *args, const char *flag) static int zone_txn_get(zone_t *zone, ctl_args_t *args) { - return zone_flag_txn_get(zone, args, NULL); + pthread_mutex_lock(&zone->cu_lock); + int ret = zone_flag_txn_get(zone, args, NULL); + pthread_mutex_unlock(&zone->cu_lock); + return ret; } static int send_changeset_part(changeset_t *ch, send_ctx_t *ctx, bool from) @@ -1233,7 +1271,7 @@ static int send_changeset(changeset_t *ch, send_ctx_t *ctx) return send_changeset_part(ch, ctx, false); } -static int zone_txn_diff(zone_t *zone, ctl_args_t *args) +static int zone_txn_diff_l(zone_t *zone, ctl_args_t *args) { if (zone->control_update == NULL) { args->suppress = true; @@ -1245,7 +1283,7 @@ static int zone_txn_diff(zone_t *zone, ctl_args_t *args) return zone_flag_txn_get(zone, args, CTL_FLAG_DIFF_ADD); } - send_ctx_t *ctx = &ctl_globals.send_ctx; + send_ctx_t *ctx = &ctl_globals[args->thread_idx].send_ctx; int ret = init_send_ctx(ctx, zone->name, args); if (ret != KNOT_EOK) { return ret; @@ -1254,6 +1292,14 @@ static int zone_txn_diff(zone_t *zone, ctl_args_t *args) return send_changeset(&zone->control_update->change, ctx); } +static int zone_txn_diff(zone_t *zone, ctl_args_t *args) +{ + pthread_mutex_lock(&zone->cu_lock); + int ret = zone_txn_diff_l(zone, args); + pthread_mutex_unlock(&zone->cu_lock); + return ret; +} + static int get_ttl(zone_t *zone, ctl_args_t *args, uint32_t *ttl) { knot_dname_storage_t owner; @@ -1297,8 +1343,8 @@ static int create_rrset(knot_rrset_t **rrset, zone_t *zone, ctl_args_t *args, const char *ttl = need_ttl ? args->data[KNOT_CTL_IDX_TTL] : NULL; // Prepare a buffer for a reconstructed record. - const size_t buff_len = sizeof(ctl_globals.txt_rr); - char *buff = ctl_globals.txt_rr; + const size_t buff_len = sizeof(ctl_globals[args->thread_idx].txt_rr); + char *buff = ctl_globals[args->thread_idx].txt_rr; // Choose default TTL if none was specified. uint32_t default_ttl = 0; @@ -1321,7 +1367,7 @@ static int create_rrset(knot_rrset_t **rrset, zone_t *zone, ctl_args_t *args, size_t rdata_len = ret; // Parse the record. - zs_scanner_t *scanner = &ctl_globals.scanner; + zs_scanner_t *scanner = &ctl_globals[args->thread_idx].scanner; if (zs_init(scanner, origin, KNOT_CLASS_IN, default_ttl) != 0 || zs_set_input_string(scanner, buff, rdata_len) != 0 || zs_parse_record(scanner) != 0 || @@ -1347,7 +1393,7 @@ parser_failed: return ret; } -static int zone_txn_set(zone_t *zone, ctl_args_t *args) +static int zone_txn_set_l(zone_t *zone, ctl_args_t *args) { if (zone->control_update == NULL) { args->suppress = true; @@ -1371,7 +1417,15 @@ static int zone_txn_set(zone_t *zone, ctl_args_t *args) return ret; } -static int zone_txn_unset(zone_t *zone, ctl_args_t *args) +static int zone_txn_set(zone_t *zone, ctl_args_t *args) +{ + pthread_mutex_lock(&zone->cu_lock); + int ret = zone_txn_set_l(zone, args); + pthread_mutex_unlock(&zone->cu_lock); + return ret; +} + +static int zone_txn_unset_l(zone_t *zone, ctl_args_t *args) { if (zone->control_update == NULL) { args->suppress = true; @@ -1421,6 +1475,14 @@ static int zone_txn_unset(zone_t *zone, ctl_args_t *args) } } +static int zone_txn_unset(zone_t *zone, ctl_args_t *args) +{ + pthread_mutex_lock(&zone->cu_lock); + int ret = zone_txn_unset_l(zone, args); + pthread_mutex_unlock(&zone->cu_lock); + return ret; +} + static bool zone_exists(const knot_dname_t *zone, void *data) { assert(zone); @@ -1487,7 +1549,7 @@ static int purge_orphan_member_cb(const knot_dname_t *member, const knot_dname_t orphan->name = (knot_dname_t *)member; orphan->server = server; - purge_flag_t params = + const purge_flag_t params = PURGE_ZONE_TIMERS | PURGE_ZONE_JOURNAL | PURGE_ZONE_KASPDB | PURGE_ZONE_BEST | PURGE_ZONE_LOG; @@ -1530,7 +1592,7 @@ static int catalog_orphans_sweep(server_t *server) knot_strerror(ret)); } } else { - log_error("can't open catalog for purging (%s)", + log_error("can not open catalog for purging (%s)", knot_strerror(ret)); } @@ -1683,7 +1745,7 @@ static int zone_purge(zone_t *zone, ctl_args_t *args) (void)zone_events_schedule_blocking(zone, ZONE_EVENT_EXPIRE, true); } - purge_flag_t params = + const purge_flag_t params = MATCH_OR_FILTER(args, CTL_FILTER_PURGE_TIMERS) * PURGE_ZONE_TIMERS | MATCH_OR_FILTER(args, CTL_FILTER_PURGE_ZONEFILE) * PURGE_ZONE_ZONEFILE | MATCH_OR_FILTER(args, CTL_FILTER_PURGE_JOURNAL) * PURGE_ZONE_JOURNAL | @@ -1695,213 +1757,82 @@ static int zone_purge(zone_t *zone, ctl_args_t *args) return selective_zone_purge(conf(), zone, params); } -static int send_stats_ctr(mod_ctr_t *ctr, uint64_t **stats_vals, unsigned threads, - ctl_args_t *args, knot_ctl_data_t *data) +int ctl_dump_ctr(stats_dump_params_t *params, stats_dump_ctx_t *ctx) { - char index[128]; - char value[32]; - - if (ctr->count == 1) { - uint64_t counter = stats_get_counter(stats_vals, ctr->offset, threads); - int ret = snprintf(value, sizeof(value), "%"PRIu64, counter); - if (ret <= 0 || ret >= sizeof(value)) { - return KNOT_ESPACE; - } - - (*data)[KNOT_CTL_IDX_ID] = NULL; - (*data)[KNOT_CTL_IDX_DATA] = value; + ctl_args_t *args = ctx->ctx; - ret = knot_ctl_send(args->ctl, KNOT_CTL_TYPE_DATA, data); - if (ret != KNOT_EOK) { - return ret; - } - } else { - bool force = ctl_has_flag(args->data[KNOT_CTL_IDX_FLAGS], - CTL_FLAG_FORCE); - - for (uint32_t i = 0; i < ctr->count; i++) { - uint64_t counter = stats_get_counter(stats_vals, ctr->offset + i, threads); - - // Skip empty counters. - if (counter == 0 && !force) { - continue; - } - - int ret; - if (ctr->idx_to_str) { - char *str = ctr->idx_to_str(i, ctr->count); - if (str == NULL) { - continue; - } - ret = snprintf(index, sizeof(index), "%s", str); - free(str); - } else { - ret = snprintf(index, sizeof(index), "%u", i); - } - if (ret <= 0 || ret >= sizeof(index)) { - return KNOT_ESPACE; - } - - ret = snprintf(value, sizeof(value), "%"PRIu64, counter); - if (ret <= 0 || ret >= sizeof(value)) { - return KNOT_ESPACE; - } - - (*data)[KNOT_CTL_IDX_ID] = index; - (*data)[KNOT_CTL_IDX_DATA] = value; - - knot_ctl_type_t type = (i == 0) ? KNOT_CTL_TYPE_DATA : - KNOT_CTL_TYPE_EXTRA; - ret = knot_ctl_send(args->ctl, type, data); - if (ret != KNOT_EOK) { - return ret; - } - } + if (ctx->item != NULL && strcasecmp(ctx->item, params->item) != 0) { + return KNOT_EOK; } + ctx->match = true; - return KNOT_EOK; -} - -static int modules_stats(list_t *query_modules, ctl_args_t *args, knot_ctl_data_t *data) -{ - if (query_modules == NULL) { + if (params->value == 0 && + !ctl_has_flag(args->data[KNOT_CTL_IDX_FLAGS], CTL_FLAG_FORCE)) { return KNOT_EOK; } - const char *section = args->data[KNOT_CTL_IDX_SECTION]; - const char *item = args->data[KNOT_CTL_IDX_ITEM]; - - bool section_found = (section == NULL) ? true : false; - bool item_found = (item == NULL) ? true : false; - - knotd_mod_t *mod; - WALK_LIST(mod, *query_modules) { - // Skip modules without statistics. - if (mod->stats_count == 0) { - continue; - } - - // Check for specific module. - if (section != NULL) { - if (section_found) { - break; - } else if (strcasecmp(mod->id->name + 1, section) == 0) { - section_found = true; - } else { - continue; - } - } - - (*data)[KNOT_CTL_IDX_SECTION] = mod->id->name + 1; - - unsigned threads = knotd_mod_threads(mod); - - for (int i = 0; i < mod->stats_count; i++) { - mod_ctr_t *ctr = mod->stats_info + i; - - // Skip empty counter. - if (ctr->name == NULL) { - continue; - } - - // Check for specific counter. - if (item != NULL) { - if (item_found) { - break; - } else if (strcasecmp(ctr->name, item) == 0) { - item_found = true; - } else { - continue; - } - } + char value[32]; + int ret = snprintf(value, sizeof(value), "%"PRIu64, params->value); + if (ret <= 0 || ret >= sizeof(value)) { + return KNOT_ESPACE; + } - (*data)[KNOT_CTL_IDX_ITEM] = ctr->name; + knot_ctl_data_t data = { + [KNOT_CTL_IDX_SECTION] = params->section, + [KNOT_CTL_IDX_ITEM] = params->item, + [KNOT_CTL_IDX_ID] = params->id, + [KNOT_CTL_IDX_ZONE] = params->zone, + [KNOT_CTL_IDX_DATA] = value, + }; - // Send the counters. - int ret = send_stats_ctr(ctr, mod->stats_vals, threads, args, data); - if (ret != KNOT_EOK) { - return ret; - } - } - } + knot_ctl_type_t type = (params->value_pos == 0) ? + KNOT_CTL_TYPE_DATA : KNOT_CTL_TYPE_EXTRA; - return (section_found && item_found) ? KNOT_EOK : KNOT_ENOENT; + return knot_ctl_send(args->ctl, type, &data); } static int common_stats(ctl_args_t *args, zone_t *zone) { - const char *section = args->data[KNOT_CTL_IDX_SECTION]; - const char *item = args->data[KNOT_CTL_IDX_ITEM]; - - char value[32]; - knot_ctl_data_t data = { - [KNOT_CTL_IDX_DATA] = value + stats_dump_ctx_t dump_ctx = { + .server = args->server, + .zone = zone, + .section = args->data[KNOT_CTL_IDX_SECTION], + .item = args->data[KNOT_CTL_IDX_ITEM], + .ctx = args, }; - knot_dname_txt_storage_t name = ""; - if (zone != NULL) { - if (knot_dname_to_str(name, zone->name, sizeof(name)) == NULL) { - return KNOT_EINVAL; - } - data[KNOT_CTL_IDX_ZONE] = name; - } - - bool found = (section == NULL) ? true : false; - - // Process zone metrics. - const char *section_name = (zone != NULL) ? "zone" : "server"; - if (section == NULL || strcasecmp(section, section_name) == 0) { - data[KNOT_CTL_IDX_SECTION] = section_name; - - const stats_item_t *items = (zone != NULL) ? zone_contents_stats : - server_stats; - for (const stats_item_t *i = items; i->name != NULL; i++) { - if (item != NULL) { - if (found) { - break; - } else if (strcmp(i->name, item) == 0) { - found = true; - } else { - continue; - } - } else { - found = true; - } +#define STATS_CHECK(ret, send) { \ + if (ret != KNOT_EOK) { \ + if ((send)) { /* Prevents duplicit zone error logs. */ \ + send_error(args, knot_strerror(ret)); \ + } \ + return ret; \ + } \ +} - data[KNOT_CTL_IDX_ITEM] = i->name; - int ret = snprintf(value, sizeof(value), "%"PRIu64, - (zone != NULL) ? i->zone_val(zone) : - i->server_val(args->server)); - if (ret <= 0 || ret >= sizeof(value)) { - ret = KNOT_ESPACE; - send_error(args, knot_strerror(ret)); - return ret; - } + if (zone == NULL) { + int ret = stats_server(ctl_dump_ctr, &dump_ctx); + STATS_CHECK(ret, true); - ret = knot_ctl_send(args->ctl, KNOT_CTL_TYPE_DATA, &data); - if (ret != KNOT_EOK) { - send_error(args, knot_strerror(ret)); - return ret; - } - } - } + ret = stats_xdp(ctl_dump_ctr, &dump_ctx); + STATS_CHECK(ret, true); - if (section == NULL || strncasecmp(section, "mod-", strlen("mod-")) == 0) { - list_t *query_modules = (zone != NULL) ? &zone->query_modules : - conf()->query_modules; - int ret = modules_stats(query_modules, args, &data); - if (ret != KNOT_EOK) { - send_error(args, knot_strerror(ret)); - return ret; - } + dump_ctx.query_modules = conf()->query_modules; + ret = stats_modules(ctl_dump_ctr, &dump_ctx); + STATS_CHECK(ret, true); + } else { + int ret = stats_zone(ctl_dump_ctr, &dump_ctx); + STATS_CHECK(ret, false); - found = true; + dump_ctx.query_modules = &zone->query_modules; + ret = stats_modules(ctl_dump_ctr, &dump_ctx); + STATS_CHECK(ret, false); } - if (!found) { - send_error(args, knot_strerror(KNOT_EINVAL)); - return KNOT_EINVAL; + if (!dump_ctx.match) { + STATS_CHECK(KNOT_EINVAL, zone == NULL); } +#undef STATS_CHECK return KNOT_EOK; } @@ -1932,6 +1863,8 @@ static int ctl_zone(ctl_args_t *args, ctl_cmd_t cmd) return zones_apply_backup(args, true); case CTL_ZONE_SIGN: return zones_apply(args, zone_sign); + case CTL_ZONE_VALIDATE: + return zones_apply(args, zone_validate); case CTL_ZONE_KEYS_LOAD: return zones_apply(args, zone_keys_load); case CTL_ZONE_KEY_ROLL: @@ -1976,6 +1909,27 @@ static int ctl_zone(ctl_args_t *args, ctl_cmd_t cmd) } } +static void check_zone_txn(zone_t *zone, const knot_dname_t **exists) +{ + if (zone->control_update != NULL) { + *exists = zone->name; + } +} + +static int check_no_zone_txn(server_t *server, const char *action) +{ + const knot_dname_t *zone_txn_exists = NULL; + knot_zonedb_foreach(server->zone_db, check_zone_txn, &zone_txn_exists); + if (zone_txn_exists != NULL) { + knot_dname_txt_storage_t zone_str; + knot_dname_to_str(zone_str, zone_txn_exists, sizeof(zone_str)); + log_warning("%s rejected due to existing transaction for zone %s", + action, zone_str); + return KNOT_TXN_EEXISTS; + } + return KNOT_EOK; +} + static int server_status(ctl_args_t *args) { const char *type = args->data[KNOT_CTL_IDX_TYPE]; @@ -1998,7 +1952,7 @@ static int server_status(ctl_args_t *args) conf()->cache.srv_xdp_threads, conf()->cache.srv_bg_threads, running_bkg_wrk, wrk_queue); } else if (strcasecmp(type, "configure") == 0) { - ret = snprintf(buff, sizeof(buff), "%s", CONFIGURE_SUMMARY); + ret = snprintf(buff, sizeof(buff), "%s", configure_summary); } else if (strcasecmp(type, "cert-key") == 0) { uint8_t pin[128]; size_t pin_len = server_cert_pin(args->server, pin, sizeof(pin)); @@ -2034,7 +1988,10 @@ static int ctl_server(ctl_args_t *args, ctl_cmd_t cmd) ret = KNOT_CTL_ESTOP; break; case CTL_RELOAD: - ret = server_reload(args->server, RELOAD_FULL); + ret = check_no_zone_txn(args->server, "server reload"); + if (ret == KNOT_EOK) { + ret = server_reload(args->server, RELOAD_FULL); + } if (ret != KNOT_EOK) { send_error(args, knot_strerror(ret)); } @@ -2171,7 +2128,10 @@ static int ctl_conf_txn(ctl_args_t *args, ctl_cmd_t cmd) switch (cmd) { case CTL_CONF_BEGIN: - ret = conf_io_begin(false); + ret = check_no_zone_txn(args->server, "config, transaction"); + if (ret == KNOT_EOK) { + ret = conf_io_begin(false); + } break; case CTL_CONF_ABORT: conf_io_abort(false); @@ -2368,56 +2328,64 @@ static int ctl_conf_modify(ctl_args_t *args, ctl_cmd_t cmd) return ret; } +typedef enum { + CTL_LOCK_NONE = 0x00, + CTL_LOCK_SRV_R = 0x01, // Can run in parallel with other R commands. + CTL_LOCK_SRV_W = 0x02, // Cannot run in parallel with other commands. +} ctl_lock_flag_t; + typedef struct { const char *name; int (*fcn)(ctl_args_t *, ctl_cmd_t); + ctl_lock_flag_t locks; } desc_t; static const desc_t cmd_table[] = { [CTL_NONE] = { "" }, - [CTL_STATUS] = { "status", ctl_server }, - [CTL_STOP] = { "stop", ctl_server }, - [CTL_RELOAD] = { "reload", ctl_server }, - [CTL_STATS] = { "stats", ctl_stats }, - - [CTL_ZONE_STATUS] = { "zone-status", ctl_zone }, - [CTL_ZONE_RELOAD] = { "zone-reload", ctl_zone }, - [CTL_ZONE_REFRESH] = { "zone-refresh", ctl_zone }, - [CTL_ZONE_RETRANSFER] = { "zone-retransfer", ctl_zone }, - [CTL_ZONE_NOTIFY] = { "zone-notify", ctl_zone }, - [CTL_ZONE_FLUSH] = { "zone-flush", ctl_zone }, - [CTL_ZONE_BACKUP] = { "zone-backup", ctl_zone }, - [CTL_ZONE_RESTORE] = { "zone-restore", ctl_zone }, - [CTL_ZONE_SIGN] = { "zone-sign", ctl_zone }, - [CTL_ZONE_KEYS_LOAD] = { "zone-keys-load", ctl_zone }, - [CTL_ZONE_KEY_ROLL] = { "zone-key-rollover", ctl_zone }, - [CTL_ZONE_KSK_SBM] = { "zone-ksk-submitted", ctl_zone }, - [CTL_ZONE_FREEZE] = { "zone-freeze", ctl_zone }, - [CTL_ZONE_THAW] = { "zone-thaw", ctl_zone }, - [CTL_ZONE_XFR_FREEZE] = { "zone-xfr-freeze", ctl_zone }, - [CTL_ZONE_XFR_THAW] = { "zone-xfr-thaw", ctl_zone }, - - [CTL_ZONE_READ] = { "zone-read", ctl_zone }, - [CTL_ZONE_BEGIN] = { "zone-begin", ctl_zone }, - [CTL_ZONE_COMMIT] = { "zone-commit", ctl_zone }, - [CTL_ZONE_ABORT] = { "zone-abort", ctl_zone }, - [CTL_ZONE_DIFF] = { "zone-diff", ctl_zone }, - [CTL_ZONE_GET] = { "zone-get", ctl_zone }, - [CTL_ZONE_SET] = { "zone-set", ctl_zone }, - [CTL_ZONE_UNSET] = { "zone-unset", ctl_zone }, - [CTL_ZONE_PURGE] = { "zone-purge", ctl_zone }, - [CTL_ZONE_STATS] = { "zone-stats", ctl_zone }, - - [CTL_CONF_LIST] = { "conf-list", ctl_conf_list }, - [CTL_CONF_READ] = { "conf-read", ctl_conf_read }, - [CTL_CONF_BEGIN] = { "conf-begin", ctl_conf_txn }, - [CTL_CONF_COMMIT] = { "conf-commit", ctl_conf_txn }, - [CTL_CONF_ABORT] = { "conf-abort", ctl_conf_txn }, - [CTL_CONF_DIFF] = { "conf-diff", ctl_conf_read }, - [CTL_CONF_GET] = { "conf-get", ctl_conf_read }, - [CTL_CONF_SET] = { "conf-set", ctl_conf_modify }, - [CTL_CONF_UNSET] = { "conf-unset", ctl_conf_modify }, + [CTL_STATUS] = { "status", ctl_server, CTL_LOCK_SRV_R }, + [CTL_STOP] = { "stop", ctl_server, CTL_LOCK_SRV_R }, + [CTL_RELOAD] = { "reload", ctl_server, CTL_LOCK_SRV_W }, + [CTL_STATS] = { "stats", ctl_stats, CTL_LOCK_SRV_R }, + + [CTL_ZONE_STATUS] = { "zone-status", ctl_zone, CTL_LOCK_SRV_R }, + [CTL_ZONE_RELOAD] = { "zone-reload", ctl_zone, CTL_LOCK_SRV_R }, + [CTL_ZONE_REFRESH] = { "zone-refresh", ctl_zone, CTL_LOCK_SRV_R }, + [CTL_ZONE_RETRANSFER] = { "zone-retransfer", ctl_zone, CTL_LOCK_SRV_R }, + [CTL_ZONE_NOTIFY] = { "zone-notify", ctl_zone, CTL_LOCK_SRV_R }, + [CTL_ZONE_FLUSH] = { "zone-flush", ctl_zone, CTL_LOCK_SRV_R }, + [CTL_ZONE_BACKUP] = { "zone-backup", ctl_zone, CTL_LOCK_SRV_W }, // Backup and restore must be exclusive as the global backup ctx is accessed. + [CTL_ZONE_RESTORE] = { "zone-restore", ctl_zone, CTL_LOCK_SRV_W }, + [CTL_ZONE_SIGN] = { "zone-sign", ctl_zone, CTL_LOCK_SRV_R }, + [CTL_ZONE_VALIDATE] = { "zone-validate", ctl_zone, CTL_LOCK_SRV_R }, + [CTL_ZONE_KEYS_LOAD] = { "zone-keys-load", ctl_zone, CTL_LOCK_SRV_R }, + [CTL_ZONE_KEY_ROLL] = { "zone-key-rollover", ctl_zone, CTL_LOCK_SRV_R }, + [CTL_ZONE_KSK_SBM] = { "zone-ksk-submitted", ctl_zone, CTL_LOCK_SRV_R }, + [CTL_ZONE_FREEZE] = { "zone-freeze", ctl_zone, CTL_LOCK_SRV_R }, + [CTL_ZONE_THAW] = { "zone-thaw", ctl_zone, CTL_LOCK_SRV_R }, + [CTL_ZONE_XFR_FREEZE] = { "zone-xfr-freeze", ctl_zone, CTL_LOCK_SRV_R }, + [CTL_ZONE_XFR_THAW] = { "zone-xfr-thaw", ctl_zone, CTL_LOCK_SRV_R }, + + [CTL_ZONE_READ] = { "zone-read", ctl_zone, CTL_LOCK_SRV_R }, + [CTL_ZONE_BEGIN] = { "zone-begin", ctl_zone, CTL_LOCK_SRV_R }, + [CTL_ZONE_COMMIT] = { "zone-commit", ctl_zone, CTL_LOCK_SRV_R }, + [CTL_ZONE_ABORT] = { "zone-abort", ctl_zone, CTL_LOCK_SRV_R }, + [CTL_ZONE_DIFF] = { "zone-diff", ctl_zone, CTL_LOCK_SRV_R }, + [CTL_ZONE_GET] = { "zone-get", ctl_zone, CTL_LOCK_SRV_R }, + [CTL_ZONE_SET] = { "zone-set", ctl_zone, CTL_LOCK_SRV_R }, + [CTL_ZONE_UNSET] = { "zone-unset", ctl_zone, CTL_LOCK_SRV_R }, + [CTL_ZONE_PURGE] = { "zone-purge", ctl_zone, CTL_LOCK_SRV_W }, + [CTL_ZONE_STATS] = { "zone-stats", ctl_zone, CTL_LOCK_SRV_R }, + + [CTL_CONF_LIST] = { "conf-list", ctl_conf_list, CTL_LOCK_SRV_R }, // Can either read live conf or conf txn. The latter would deserve CTL_LOCK_SRV_W, but when conf txn exists, all cmds are done by single thread anyway. + [CTL_CONF_READ] = { "conf-read", ctl_conf_read, CTL_LOCK_SRV_R }, + [CTL_CONF_BEGIN] = { "conf-begin", ctl_conf_txn, CTL_LOCK_SRV_W }, // It's locked only during conf-begin, not for the whole duration of the transaction. + [CTL_CONF_COMMIT] = { "conf-commit", ctl_conf_txn, CTL_LOCK_SRV_W }, + [CTL_CONF_ABORT] = { "conf-abort", ctl_conf_txn, CTL_LOCK_SRV_W }, + [CTL_CONF_DIFF] = { "conf-diff", ctl_conf_read, CTL_LOCK_SRV_W }, + [CTL_CONF_GET] = { "conf-get", ctl_conf_read, CTL_LOCK_SRV_W }, + [CTL_CONF_SET] = { "conf-set", ctl_conf_modify, CTL_LOCK_SRV_W }, + [CTL_CONF_UNSET] = { "conf-unset", ctl_conf_modify, CTL_LOCK_SRV_W }, }; #define MAX_CTL_CODE (sizeof(cmd_table) / sizeof(desc_t) - 1) @@ -2446,13 +2414,52 @@ ctl_cmd_t ctl_str_to_cmd(const char *cmd_str) return CTL_NONE; } +static int ctl_lock(server_t *server, ctl_lock_flag_t flags, uint64_t timeout_ms) +{ + struct timespec ts; + int ret = clock_gettime(CLOCK_REALTIME, &ts); + if (ret != 0) { + return KNOT_ERROR; + } + ts.tv_sec += timeout_ms / 1000; + ts.tv_nsec += (timeout_ms % 1000) * 1000000LU; + + if ((flags & CTL_LOCK_SRV_W)) { + assert(!(flags & CTL_LOCK_SRV_R)); +#if !defined(__APPLE__) + ret = pthread_rwlock_timedwrlock(&server->ctl_lock, &ts); +#else + ret = pthread_rwlock_wrlock(&server->ctl_lock); +#endif + } + if ((flags & CTL_LOCK_SRV_R)) { +#if !defined(__APPLE__) + ret = pthread_rwlock_timedrdlock(&server->ctl_lock, &ts); +#else + ret = pthread_rwlock_rdlock(&server->ctl_lock); +#endif + } + return (ret != 0 ? KNOT_EBUSY : KNOT_EOK); +} + +static void ctl_unlock(server_t *server) +{ + pthread_rwlock_unlock(&server->ctl_lock); +} + int ctl_exec(ctl_cmd_t cmd, ctl_args_t *args) { if (args == NULL) { return KNOT_EINVAL; } - return cmd_table[cmd].fcn(args, cmd); + int ret = ctl_lock(args->server, cmd_table[cmd].locks, conf()->cache.ctl_timeout); + if (ret == KNOT_EOK) { + ret = cmd_table[cmd].fcn(args, cmd); + ctl_unlock(args->server); + } + + return ret; } bool ctl_has_flag(const char *flags, const char *flag) diff --git a/src/knot/ctl/commands.h b/src/knot/ctl/commands.h index ed7e75c..b0f33d8 100644 --- a/src/knot/ctl/commands.h +++ b/src/knot/ctl/commands.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -87,6 +87,7 @@ typedef enum { CTL_ZONE_BACKUP, CTL_ZONE_RESTORE, CTL_ZONE_SIGN, + CTL_ZONE_VALIDATE, CTL_ZONE_KEYS_LOAD, CTL_ZONE_KEY_ROLL, CTL_ZONE_KSK_SBM, @@ -124,6 +125,7 @@ typedef struct { knot_ctl_data_t data; server_t *server; bool suppress; // Suppress error reporting in the "all zones" ctl commands. + unsigned thread_idx; } ctl_args_t; /*! diff --git a/src/knot/ctl/process.c b/src/knot/ctl/process.c index 50fde21..9e6e0df 100644 --- a/src/knot/ctl/process.c +++ b/src/knot/ctl/process.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -20,7 +20,7 @@ #include "libknot/error.h" #include "contrib/string.h" -int ctl_process(knot_ctl_t *ctl, server_t *server) +int ctl_process(knot_ctl_t *ctl, server_t *server, int thread_idx, bool *exclusive) { if (ctl == NULL || server == NULL) { return KNOT_EINVAL; @@ -29,7 +29,8 @@ int ctl_process(knot_ctl_t *ctl, server_t *server) ctl_args_t args = { .ctl = ctl, .type = KNOT_CTL_TYPE_END, - .server = server + .server = server, + .thread_idx = thread_idx, }; // Strip redundant/unprocessed data units in the current block. @@ -90,11 +91,21 @@ int ctl_process(knot_ctl_t *ctl, server_t *server) continue; } + if ((cmd == CTL_CONF_COMMIT || cmd == CTL_CONF_ABORT) && !*exclusive) { + log_ctl_warning("control, invalid reception of '%s'", cmd_name); + continue; + } + // Execute the command. int cmd_ret = ctl_exec(cmd, &args); switch (cmd_ret) { case KNOT_EOK: strip = false; + if (cmd == CTL_CONF_BEGIN) { + *exclusive = true; + } else if (cmd == CTL_CONF_COMMIT || cmd == CTL_CONF_ABORT) { + *exclusive = false; + } case KNOT_CTL_ESTOP: case KNOT_CTL_EZONE: // KNOT_CTL_EZONE - don't change strip, but don't be reported diff --git a/src/knot/ctl/process.h b/src/knot/ctl/process.h index ab0f75f..2ae6ea0 100644 --- a/src/knot/ctl/process.h +++ b/src/knot/ctl/process.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -19,12 +19,16 @@ #include "libknot/libknot.h" #include "knot/server/server.h" +#define CTL_MAX_CONCURRENT 8 // Number of CTL threads EXCLUDING the main thread which can also process CTL. + /*! * Processes incoming control commands. * - * \param[in] ctl Control context. - * \param[in] server Server instance. + * \param[in] ctl Control context. + * \param[in] server Server instance. + * \param[in] thread_idx Index of a thread which performs the operation. + * \param[out] exclusive All following CTLs shall (not) be processed exclusively by this thread. * * \return Error code, KNOT_EOK if successful. */ -int ctl_process(knot_ctl_t *ctl, server_t *server); +int ctl_process(knot_ctl_t *ctl, server_t *server, int thread_idx, bool *exclusive); diff --git a/src/knot/dnssec/context.c b/src/knot/dnssec/context.c index 1a19f68..24b41f7 100644 --- a/src/knot/dnssec/context.c +++ b/src/knot/dnssec/context.c @@ -213,11 +213,13 @@ int kdnssec_ctx_init(conf_t *conf, kdnssec_ctx_t *ctx, const knot_dname_t *zone_ goto init_error; } - ctx->policy = calloc(1, sizeof(*ctx->policy)); + ctx->policy = calloc(1, sizeof(*ctx->policy) + sizeof(*ctx->stats)); if (ctx->policy == NULL) { ret = KNOT_ENOMEM; goto init_error; } + ctx->stats = (void *)ctx->policy + sizeof(*ctx->policy); + knot_spin_init(&ctx->stats->lock); ret = kasp_db_get_saved_ttls(ctx->kasp_db, zone_name, &ctx->policy->saved_max_ttl, @@ -287,6 +289,7 @@ void kdnssec_ctx_deinit(kdnssec_ctx_t *ctx) } if (ctx->policy != NULL) { + knot_spin_destroy(&ctx->stats->lock); free(ctx->policy->string); knot_dynarray_foreach(parent, knot_kasp_parent_t, i, ctx->policy->parents) { free(i->addr); @@ -331,18 +334,22 @@ int kdnssec_validation_ctx(conf_t *conf, kdnssec_ctx_t *ctx, const zone_contents return KNOT_ENOMEM; } - ctx->policy = calloc(1, sizeof(*ctx->policy)); + ctx->policy = calloc(1, sizeof(*ctx->policy) + sizeof(*ctx->stats)); if (ctx->policy == NULL) { free(ctx->zone); return KNOT_ENOMEM; } + ctx->stats = (void *)ctx->policy + sizeof(*ctx->policy); + knot_spin_init(&ctx->stats->lock); policy_from_zone(ctx->policy, zone); if (conf != NULL) { conf_val_t policy_id = conf_zone_get(conf, C_DNSSEC_POLICY, zone->apex->owner); conf_id_fix_default(&policy_id); - conf_val_t num_threads = conf_id_get(conf, C_POLICY, C_SIGNING_THREADS, &policy_id); - ctx->policy->signing_threads = conf_int(&num_threads); + conf_val_t val = conf_id_get(conf, C_POLICY, C_SIGNING_THREADS, &policy_id); + ctx->policy->signing_threads = conf_int(&val); + val = conf_id_get(conf, C_POLICY, C_RRSIG_REFRESH, &policy_id); + ctx->policy->rrsig_refresh_before = conf_int_alt(&val, true); } else { ctx->policy->signing_threads = MAX(dt_optimal_size(), 1); } diff --git a/src/knot/dnssec/context.h b/src/knot/dnssec/context.h index 756bc56..2d126db 100644 --- a/src/knot/dnssec/context.h +++ b/src/knot/dnssec/context.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -16,14 +16,20 @@ #pragma once -#include <time.h> - #include "libdnssec/keystore.h" - +#include "contrib/spinlock.h" +#include "contrib/time.h" #include "knot/conf/conf.h" #include "knot/dnssec/kasp/kasp_zone.h" #include "knot/dnssec/kasp/policy.h" +typedef struct { + size_t rrsig_count; + knot_time_t expire; + + knot_spin_t lock; +} zone_sign_stats_t; + /*! * \brief DNSSEC signing context. */ @@ -38,6 +44,8 @@ typedef struct { char *kasp_zone_path; + zone_sign_stats_t *stats; + bool rrsig_drop_existing; bool keep_deleted_keys; bool keytag_conflict; diff --git a/src/knot/dnssec/ds_query.c b/src/knot/dnssec/ds_query.c index 2ac91cc..0b85247 100644 --- a/src/knot/dnssec/ds_query.c +++ b/src/knot/dnssec/ds_query.c @@ -28,8 +28,8 @@ #define DS_CHECK_LOG(priority, zone, remote, flags, fmt, ...) \ ns_log(priority, zone, LOG_OPERATION_DS_CHECK, LOG_DIRECTION_OUT, &(remote)->addr, \ - ((flags) & KNOT_REQUESTOR_QUIC) ? KNOTD_QUERY_PROTO_QUIC : KNOTD_QUERY_PROTO_TCP, \ - ((flags) & KNOT_REQUESTOR_REUSED), (remote)->key.name, fmt, ## __VA_ARGS__) + flags2proto(flags), ((flags) & KNOT_REQUESTOR_REUSED), (remote)->key.name, \ + fmt, ## __VA_ARGS__) static bool match_key_ds(knot_kasp_key_t *key, knot_rdata_t *ds) { diff --git a/src/knot/dnssec/key-events.c b/src/knot/dnssec/key-events.c index 58d7ec0..db762b6 100644 --- a/src/knot/dnssec/key-events.c +++ b/src/knot/dnssec/key-events.c @@ -17,8 +17,8 @@ #include <assert.h> #include "contrib/macros.h" +#include "knot/common/dbus.h" #include "knot/common/log.h" -#include "knot/common/systemd.h" #include "knot/dnssec/kasp/keystate.h" #include "knot/dnssec/key-events.h" #include "knot/dnssec/policy.h" @@ -881,7 +881,7 @@ int knot_dnssec_key_rollover(kdnssec_ctx_t *ctx, zone_sign_roll_flags_t flags, if (ret == KNOT_EOK && reschedule->keys_changed) { ret = kdnssec_ctx_commit(ctx); if (ret == KNOT_EOK && (ctx->dbus_event & DBUS_EVENT_KEYS_UPDATED)) { - systemd_emit_keys_updated(ctx->zone->dname); + dbus_emit_keys_updated(ctx->zone->dname); } } @@ -891,7 +891,7 @@ int knot_dnssec_key_rollover(kdnssec_ctx_t *ctx, zone_sign_roll_flags_t flags, log_fmt_zone(LOG_NOTICE, LOG_SOURCE_ZONE, ctx->zone->dname, param, "DNSSEC, KSK submission, waiting for confirmation"); if (ctx->dbus_event & DBUS_EVENT_ZONE_SUBMISSION) { - systemd_emit_zone_submission(ctx->zone->dname, ready_keytag, ready_keyid); + dbus_emit_zone_submission(ctx->zone->dname, ready_keytag, ready_keyid); } } diff --git a/src/knot/dnssec/key_records.c b/src/knot/dnssec/key_records.c index 9b22f7a..366ab4a 100644 --- a/src/knot/dnssec/key_records.c +++ b/src/knot/dnssec/key_records.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -189,7 +189,7 @@ int key_records_dump(char **buf, size_t *buf_size, const key_records_t *r, bool return ret >= 0 ? KNOT_EOK : ret; } -int key_records_sign(const zone_key_t *key, key_records_t *r, const kdnssec_ctx_t *kctx, knot_time_t *expires) +int key_records_sign(const zone_key_t *key, key_records_t *r, const kdnssec_ctx_t *kctx) { dnssec_sign_ctx_t *sign_ctx; int ret = dnssec_sign_new(&sign_ctx, key->key); @@ -198,20 +198,20 @@ int key_records_sign(const zone_key_t *key, key_records_t *r, const kdnssec_ctx_ } if (!knot_rrset_empty(&r->dnskey) && knot_zone_sign_use_key(key, &r->dnskey)) { - ret = knot_sign_rrset(&r->rrsig, &r->dnskey, key->key, sign_ctx, kctx, NULL, expires); + ret = knot_sign_rrset(&r->rrsig, &r->dnskey, key->key, sign_ctx, kctx, NULL); } if (ret == KNOT_EOK && !knot_rrset_empty(&r->cdnskey) && knot_zone_sign_use_key(key, &r->cdnskey)) { - ret = knot_sign_rrset(&r->rrsig, &r->cdnskey, key->key, sign_ctx, kctx, NULL, expires); + ret = knot_sign_rrset(&r->rrsig, &r->cdnskey, key->key, sign_ctx, kctx, NULL); } if (ret == KNOT_EOK && !knot_rrset_empty(&r->cds) && knot_zone_sign_use_key(key, &r->cds)) { - ret = knot_sign_rrset(&r->rrsig, &r->cds, key->key, sign_ctx, kctx, NULL, expires); + ret = knot_sign_rrset(&r->rrsig, &r->cds, key->key, sign_ctx, kctx, NULL); } dnssec_sign_free(sign_ctx); return ret; } -int key_records_verify(key_records_t *r, kdnssec_ctx_t *kctx, knot_time_t timestamp) +int key_records_verify(key_records_t *r, kdnssec_ctx_t *kctx, knot_time_t timestamp, knot_time_t min_valid) { kctx->now = timestamp; int ret = kasp_zone_keys_from_rr(kctx->zone, &r->dnskey.rrs, false, &kctx->keytag_conflict); @@ -224,12 +224,17 @@ int key_records_verify(key_records_t *r, kdnssec_ctx_t *kctx, knot_time_t timest return KNOT_ENOMEM; } - ret = knot_validate_rrsigs(&r->dnskey, &r->rrsig, sign_ctx, false); + knot_time_t until = 0; + ret = knot_validate_rrsigs(&r->dnskey, &r->rrsig, sign_ctx, false, &until); if (ret == KNOT_EOK && !knot_rrset_empty(&r->cdnskey)) { - ret = knot_validate_rrsigs(&r->cdnskey, &r->rrsig, sign_ctx, false); + ret = knot_validate_rrsigs(&r->cdnskey, &r->rrsig, sign_ctx, false, &until); } if (ret == KNOT_EOK && !knot_rrset_empty(&r->cds)) { - ret = knot_validate_rrsigs(&r->cds, &r->rrsig, sign_ctx, false); + ret = knot_validate_rrsigs(&r->cds, &r->rrsig, sign_ctx, false, &until); + } + + if (ret == KNOT_EOK && knot_time_lt(until, min_valid)) { + ret = KNOT_ESOON_EXPIRE; } zone_sign_ctx_free(sign_ctx); diff --git a/src/knot/dnssec/key_records.h b/src/knot/dnssec/key_records.h index b53ed86..dd28b4f 100644 --- a/src/knot/dnssec/key_records.h +++ b/src/knot/dnssec/key_records.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -39,10 +39,10 @@ int key_records_intersect(key_records_t *r, const key_records_t *against); int key_records_dump(char **buf, size_t *buf_size, const key_records_t *r, bool verbose); -int key_records_sign(const zone_key_t *key, key_records_t *r, const kdnssec_ctx_t *kctx, knot_time_t *expires); +int key_records_sign(const zone_key_t *key, key_records_t *r, const kdnssec_ctx_t *kctx); // WARNING this modifies 'kctx' with updated timestamp and with zone_keys from r->dnskey -int key_records_verify(key_records_t *r, kdnssec_ctx_t *kctx, knot_time_t timestamp); +int key_records_verify(key_records_t *r, kdnssec_ctx_t *kctx, knot_time_t timestamp, knot_time_t min_valid); size_t key_records_serialized_size(const key_records_t *r); diff --git a/src/knot/dnssec/rrset-sign.c b/src/knot/dnssec/rrset-sign.c index 4c9e904..1dc9edc 100644 --- a/src/knot/dnssec/rrset-sign.c +++ b/src/knot/dnssec/rrset-sign.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -157,13 +157,13 @@ static int sign_ctx_add_self(dnssec_sign_ctx_t *ctx, const uint8_t *rdata) */ static int sign_ctx_add_records(dnssec_sign_ctx_t *ctx, const knot_rrset_t *covered) { - size_t rrwl = knot_rrset_size(covered); + size_t rrwl = knot_rrset_size_estimate(covered); uint8_t *rrwf = malloc(rrwl); if (!rrwf) { return KNOT_ENOMEM; } - int written = knot_rrset_to_wire_extra(covered, rrwf, rrwl, 0, NULL, KNOT_PF_BUFENOUGH); + int written = knot_rrset_to_wire_extra(covered, rrwf, rrwl, 0, NULL, 0); if (written < 0) { free(rrwf); return written; @@ -263,7 +263,7 @@ static int rrsigs_create_rdata(knot_rrset_t *rrsigs, dnssec_sign_ctx_t *ctx, int knot_sign_rrset(knot_rrset_t *rrsigs, const knot_rrset_t *covered, const dnssec_key_t *key, dnssec_sign_ctx_t *sign_ctx, - const kdnssec_ctx_t *dnssec_ctx, knot_mm_t *mm, knot_time_t *expires) + const kdnssec_ctx_t *dnssec_ctx, knot_mm_t *mm) { if (knot_rrset_empty(covered) || !key || !sign_ctx || !dnssec_ctx || rrsigs->type != KNOT_RRTYPE_RRSIG || @@ -279,8 +279,11 @@ int knot_sign_rrset(knot_rrset_t *rrsigs, const knot_rrset_t *covered, int ret = rrsigs_create_rdata(rrsigs, sign_ctx, covered, key, (uint32_t)sig_incept, (uint32_t)sig_expire, sign_flags, mm); - if (ret == KNOT_EOK && expires != NULL) { - *expires = knot_time_min(*expires, sig_expire); + if (ret == KNOT_EOK) { + knot_spin_lock(&dnssec_ctx->stats->lock); + dnssec_ctx->stats->rrsig_count++; + dnssec_ctx->stats->expire = knot_time_min(dnssec_ctx->stats->expire, sig_expire); + knot_spin_unlock(&dnssec_ctx->stats->lock); } return ret; } @@ -300,7 +303,7 @@ int knot_sign_rrset2(knot_rrset_t *rrsigs, const knot_rrset_t *rrset, } int ret = knot_sign_rrset(rrsigs, rrset, key->key, sign_ctx->sign_ctxs[i], - sign_ctx->dnssec_ctx, mm, NULL); + sign_ctx->dnssec_ctx, mm); if (ret != KNOT_EOK) { return ret; } diff --git a/src/knot/dnssec/rrset-sign.h b/src/knot/dnssec/rrset-sign.h index 8e00402..ba0f027 100644 --- a/src/knot/dnssec/rrset-sign.h +++ b/src/knot/dnssec/rrset-sign.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -31,7 +31,6 @@ * \param sign_ctx Signing context. * \param dnssec_ctx DNSSEC context. * \param mm Memory context. - * \param expires Out: When will the new RRSIG expire. * * \return Error code, KNOT_EOK if successful. */ @@ -40,8 +39,7 @@ int knot_sign_rrset(knot_rrset_t *rrsigs, const dnssec_key_t *key, dnssec_sign_ctx_t *sign_ctx, const kdnssec_ctx_t *dnssec_ctx, - knot_mm_t *mm, - knot_time_t *expires); + knot_mm_t *mm); /*! * \brief Create RRSIG RR for given RR set, choose which key to use. diff --git a/src/knot/dnssec/zone-events.c b/src/knot/dnssec/zone-events.c index faf093d..2ca35ac 100644 --- a/src/knot/dnssec/zone-events.c +++ b/src/knot/dnssec/zone-events.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -20,6 +20,7 @@ #include "libdnssec/random.h" #include "libknot/libknot.h" #include "knot/conf/conf.h" +#include "knot/common/dbus.h" #include "knot/common/log.h" #include "knot/dnssec/key-events.h" #include "knot/dnssec/key_records.h" @@ -157,7 +158,6 @@ int knot_dnssec_zone_sign(zone_update_t *update, const knot_dname_t *zone_name = update->new_cont->apex->owner; kdnssec_ctx_t ctx = { 0 }; zone_keyset_t keyset = { 0 }; - knot_time_t zone_expire = 0; int result = kdnssec_ctx_init(conf, &ctx, zone_name, zone_kaspdb(update->zone), NULL); if (result != KNOT_EOK) { @@ -259,7 +259,7 @@ int knot_dnssec_zone_sign(zone_update_t *update, goto done; } - result = knot_zone_sign(update, &keyset, &ctx, &zone_expire); + result = knot_zone_sign(update, &keyset, &ctx); if (result != KNOT_EOK) { log_zone_error(zone_name, "DNSSEC, failed to sign zone content (%s)", knot_strerror(result)); @@ -302,13 +302,14 @@ int knot_dnssec_zone_sign(zone_update_t *update, } } - log_zone_info(zone_name, "DNSSEC, successfully signed, serial %u", - zone_contents_serial(update->new_cont)); + log_zone_info(zone_name, "DNSSEC, successfully signed, serial %u, new RRSIGs %zu", + zone_contents_serial(update->new_cont), ctx.stats->rrsig_count); done: if (result == KNOT_EOK) { - reschedule->next_sign = schedule_next(&ctx, &keyset, ctx.offline_next_time, zone_expire); + reschedule->next_sign = schedule_next(&ctx, &keyset, ctx.offline_next_time, ctx.stats->expire); reschedule->plan_dnskey_sync = ctx.policy->has_dnskey_sync; + update->new_cont->dnssec_expire = ctx.stats->expire; } else { reschedule->next_sign = knot_dnssec_failover_delay(&ctx); reschedule->next_rollover = 0; @@ -329,7 +330,6 @@ int knot_dnssec_sign_update(zone_update_t *update, conf_t *conf) const knot_dname_t *zone_name = update->new_cont->apex->owner; kdnssec_ctx_t ctx = { 0 }; zone_keyset_t keyset = { 0 }; - knot_time_t zone_expire = 0; int result = kdnssec_ctx_init(conf, &ctx, zone_name, zone_kaspdb(update->zone), NULL); if (result != KNOT_EOK) { @@ -381,7 +381,7 @@ int knot_dnssec_sign_update(zone_update_t *update, conf_t *conf) goto done; } - result = knot_zone_sign_update(update, &keyset, &ctx, &zone_expire); + result = knot_zone_sign_update(update, &keyset, &ctx); if (result != KNOT_EOK) { log_zone_error(zone_name, "DNSSEC, failed to sign changeset (%s)", knot_strerror(result)); @@ -434,17 +434,18 @@ int knot_dnssec_sign_update(zone_update_t *update, conf_t *conf) } } - log_zone_info(zone_name, "DNSSEC, incrementally signed, serial %u", - zone_contents_serial(update->new_cont)); + log_zone_info(zone_name, "DNSSEC, incrementally signed, serial %u, new RRSIGs %zu", + zone_contents_serial(update->new_cont), ctx.stats->rrsig_count); done: if (result == KNOT_EOK) { - knot_time_t next = knot_time_min(ctx.offline_next_time, zone_expire); + knot_time_t next = knot_time_min(ctx.offline_next_time, ctx.stats->expire); // NOTE: this is usually NOOP since signing planned earlier zone_events_schedule_at(update->zone, ZONE_EVENT_DNSSEC, (time_t)(next ? next : -1)); if (ctx.policy->has_dnskey_sync) { zone_events_schedule_now(update->zone, ZONE_EVENT_DNSKEY_SYNC); } + update->new_cont->dnssec_expire = knot_time_min(update->zone->contents->dnssec_expire, ctx.stats->expire); } free_zone_keys(&keyset); @@ -462,25 +463,83 @@ knot_time_t knot_dnssec_failover_delay(const kdnssec_ctx_t *ctx) } } -int knot_dnssec_validate_zone(zone_update_t *update, conf_t *conf, knot_time_t now, bool incremental) +static void log_validation_error(zone_update_t *update, const char *msg_valid, + int ret, bool warning) +{ + unsigned level = warning ? LOG_WARNING : LOG_ERR; + + log_fmt_zone(level, LOG_SOURCE_ZONE, update->zone->name, NULL, + "DNSSEC, %svalidation failed (%s)", msg_valid, knot_strerror(ret)); + + char type_str[16]; + knot_dname_txt_storage_t name_str; + if (knot_dname_to_str(name_str, update->validation_hint.node, sizeof(name_str)) != NULL && + knot_rrtype_to_string(update->validation_hint.rrtype, type_str, sizeof(type_str)) >= 0) { + log_fmt_zone(level, LOG_SOURCE_ZONE, update->zone->name, NULL, + "DNSSEC, validation hint: %s %s", name_str, type_str); + } +} + +int knot_dnssec_validate_zone(zone_update_t *update, conf_t *conf, + knot_time_t now, bool incremental, bool log_plan) { kdnssec_ctx_t ctx = { 0 }; int ret = kdnssec_validation_ctx(conf, &ctx, update->new_cont); + if (ret != KNOT_EOK) { + goto end; + } if (now != 0) { ctx.now = now; } + + ret = knot_zone_check_nsec_chain(update, &ctx, incremental); if (ret == KNOT_EOK) { - ret = knot_zone_check_nsec_chain(update, &ctx, incremental); - } - if (ret == KNOT_EOK) { - knot_time_t unused = 0; assert(ctx.validation_mode); if (incremental) { - ret = knot_zone_sign_update(update, NULL, &ctx, &unused); + ret = knot_zone_sign_update(update, NULL, &ctx); } else { - ret = knot_zone_sign(update, NULL, &ctx, &unused); + ret = knot_zone_sign(update, NULL, &ctx); } } +end: + if (log_plan) { + const char *msg_valid = incremental ? "incremental " : ""; + if (ret != KNOT_EOK) { + log_validation_error(update, msg_valid, ret, false); + if (conf->cache.srv_dbus_event & DBUS_EVENT_ZONE_INVALID) { + dbus_emit_zone_invalid(update->zone->name, 0); + } + } else if (update->validation_hint.warning != KNOT_EOK) { + log_validation_error(update, msg_valid, update->validation_hint.warning, true); + if (conf->cache.srv_dbus_event & DBUS_EVENT_ZONE_INVALID) { + dbus_emit_zone_invalid(update->zone->name, update->validation_hint.remaining_secs); + } + } else { + log_zone_info(update->zone->name, "DNSSEC, %svalidation successful, checked RRSIGs %zu", + msg_valid, ctx.stats->rrsig_count); + } + + conf_val_t val = conf_zone_get(conf, C_DNSSEC_VALIDATION, update->zone->name); + bool configured = conf_bool(&val); + bool bogus = (ret != KNOT_EOK); + bool running = (update->zone->contents == update->new_cont); + bool may_expire = zone_is_slave(conf, update->zone); + knot_time_t expire = (ctx.stats != NULL ? ctx.stats->expire : 0); + assert(bogus || knot_time_geq(expire, ctx.now)); + + if (running && bogus && may_expire) { + zone_events_schedule_now(update->zone, ZONE_EVENT_EXPIRE); + } + if (configured && !bogus) { + if (!incremental) { + zone_events_schedule_at(update->zone, ZONE_EVENT_VALIDATE, 0); // cancel previously planned re-check when fully re-checked + } + zone_events_schedule_at(update->zone, ZONE_EVENT_VALIDATE, // this works for incremental verify as well, re-planning on later + knot_time_add(expire, 1)); // is a NOOP, sooner is proper + } + } + kdnssec_ctx_deinit(&ctx); + return ret; } diff --git a/src/knot/dnssec/zone-events.h b/src/knot/dnssec/zone-events.h index 462f87a..2f75614 100644 --- a/src/knot/dnssec/zone-events.h +++ b/src/knot/dnssec/zone-events.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -16,10 +16,7 @@ #pragma once -#include <time.h> - -#include "knot/zone/zone.h" -#include "knot/updates/changesets.h" +#include "contrib/time.h" #include "knot/updates/zone-update.h" #include "knot/dnssec/context.h" @@ -54,17 +51,6 @@ typedef struct { } zone_sign_reschedule_t; /*! - * \brief Generate/rollover keys in keystore as needed. - * - * \param kctx Pointers to the keytore, policy, etc. - * \param zone_name Zone name. - * - * \return Error code, KNOT_EOK if successful. - */ -int knot_dnssec_sign_process_events(const kdnssec_ctx_t *kctx, - const knot_dname_t *zone_name); - -/*! * \brief DNSSEC re-sign zone, store new records into changeset. Valid signatures * and NSEC(3) records will not be changed. * @@ -130,7 +116,9 @@ knot_time_t knot_dnssec_failover_delay(const kdnssec_ctx_t *ctx); * \param conf Knot configuration. * \param now If not zero: adjust "now" to this timestamp. * \param incremental Try to validate incrementally. + * \param log_plan Log the result and plan subsequent validation event. * * \return KNOT_E* */ -int knot_dnssec_validate_zone(zone_update_t *update, conf_t *conf, knot_time_t now, bool incremental); +int knot_dnssec_validate_zone(zone_update_t *update, conf_t *conf, + knot_time_t now, bool incremental, bool log_plan); diff --git a/src/knot/dnssec/zone-sign.c b/src/knot/dnssec/zone-sign.c index 62f809e..3cd2420 100644 --- a/src/knot/dnssec/zone-sign.c +++ b/src/knot/dnssec/zone-sign.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -209,7 +209,6 @@ bool rrsig_covers_type(const knot_rrset_t *rrsig, uint16_t type) * \param skip_crypto All RRSIGs in this node have been verified, just check validity. * \param changeset Changeset to be updated. * \param update Zone update to be updated. Exactly one of "changeset" and "update" must be NULL! - * \param expires_at Earliest RRSIG expiration. * * \return Error code, KNOT_EOK if successful. */ @@ -218,8 +217,7 @@ static int add_missing_rrsigs(const knot_rrset_t *covered, zone_sign_ctx_t *sign_ctx, bool skip_crypto, changeset_t *changeset, - zone_update_t *update, - knot_time_t *expires_at) + zone_update_t *update) { assert(!knot_rrset_empty(covered)); assert(sign_ctx); @@ -258,11 +256,14 @@ static int add_missing_rrsigs(const knot_rrset_t *covered, sign_ctx->dnssec_ctx, refresh, skip_crypto, NULL, &valid_at)) { knot_rdata_t *valid_rr = knot_rdataset_at(&rrsigs->rrs, valid_at); result = knot_rdataset_remove(&to_remove.rrs, valid_rr, NULL); - note_earliest_expiration(valid_rr, sign_ctx->dnssec_ctx->now, expires_at); + knot_spin_lock(&sign_ctx->dnssec_ctx->stats->lock); + note_earliest_expiration(valid_rr, sign_ctx->dnssec_ctx->now, + &sign_ctx->dnssec_ctx->stats->expire); + knot_spin_unlock(&sign_ctx->dnssec_ctx->stats->lock); continue; } result = knot_sign_rrset(&to_add, covered, key->key, sign_ctx->sign_ctxs[i], - sign_ctx->dnssec_ctx, NULL, expires_at); + sign_ctx->dnssec_ctx, NULL); } if (!knot_rrset_empty(&to_remove) && result == KNOT_EOK) { @@ -306,9 +307,10 @@ static bool key_used(bool ksk, bool zsk, uint16_t type, int knot_validate_rrsigs(const knot_rrset_t *covered, const knot_rrset_t *rrsigs, zone_sign_ctx_t *sign_ctx, - bool skip_crypto) + bool skip_crypto, + knot_time_t *valid_until) { - if (covered == NULL || rrsigs == NULL || sign_ctx == NULL) { + if (covered == NULL || rrsigs == NULL || sign_ctx == NULL || valid_until == NULL) { return KNOT_EINVAL; } @@ -327,7 +329,14 @@ int knot_validate_rrsigs(const knot_rrset_t *covered, if (valid_signature_exists(covered, rrsigs, key->key, sign_ctx->sign_ctxs[i], sign_ctx->dnssec_ctx, 0, skip_crypto, val_inval_map, &valid_at)) { valid_exists = true; + knot_rdata_t *valid_rr = knot_rdataset_at(&rrsigs->rrs, valid_at); + note_earliest_expiration(valid_rr, sign_ctx->dnssec_ctx->now, valid_until); } + + knot_spin_lock(&sign_ctx->dnssec_ctx->stats->lock); + sign_ctx->dnssec_ctx->stats->rrsig_count++; + sign_ctx->dnssec_ctx->stats->expire = knot_time_min(sign_ctx->dnssec_ctx->stats->expire, *valid_until); + knot_spin_unlock(&sign_ctx->dnssec_ctx->stats->lock); } for (int i = 0; i < rrsigs->rrs.count; i++) { @@ -398,7 +407,7 @@ static int force_resign_rrset(const knot_rrset_t *covered, } } - return add_missing_rrsigs(covered, NULL, sign_ctx, false, changeset, NULL, NULL); + return add_missing_rrsigs(covered, NULL, sign_ctx, false, changeset, NULL); } /*! @@ -409,7 +418,6 @@ static int force_resign_rrset(const knot_rrset_t *covered, * \param sign_ctx Local zone signing context. * \param skip_crypto All RRSIGs in this node have been verified, just check validity. * \param changeset Changeset to be updated. - * \param expires_at Current earliest expiration, will be updated. * * \return Error code, KNOT_EOK if successful. */ @@ -417,12 +425,11 @@ static int resign_rrset(const knot_rrset_t *covered, const knot_rrset_t *rrsigs, zone_sign_ctx_t *sign_ctx, bool skip_crypto, - changeset_t *changeset, - knot_time_t *expires_at) + changeset_t *changeset) { assert(!knot_rrset_empty(covered)); - return add_missing_rrsigs(covered, rrsigs, sign_ctx, skip_crypto, changeset, NULL, expires_at); + return add_missing_rrsigs(covered, rrsigs, sign_ctx, skip_crypto, changeset, NULL); } static int remove_standalone_rrsigs(const zone_node_t *node, @@ -463,14 +470,13 @@ static int remove_standalone_rrsigs(const zone_node_t *node, * \param node Node to be signed. * \param sign_ctx Local zone signing context. * \param changeset Changeset to be updated. - * \param expires_at Current earliest expiration, will be updated. + * \param hint Out: if DNSSEC validation failed, hint why and where. * * \return Error code, KNOT_EOK if successful. */ static int sign_node_rrsets(const zone_node_t *node, zone_sign_ctx_t *sign_ctx, changeset_t *changeset, - knot_time_t *expires_at, dnssec_validation_hint_t *hint) { assert(node); @@ -499,17 +505,25 @@ static int sign_node_rrsets(const zone_node_t *node, } if (sign_ctx->dnssec_ctx->validation_mode) { - result = knot_validate_rrsigs(&rrset, &rrsigs, sign_ctx, skip_crypto); + knot_time_t until = 0; + result = knot_validate_rrsigs(&rrset, &rrsigs, sign_ctx, skip_crypto, &until); + knot_time_t diff = knot_time_diff(until, sign_ctx->dnssec_ctx->now); if (result != KNOT_EOK) { hint->node = node->owner; hint->rrtype = rrset.type; + } else if (diff < sign_ctx->dnssec_ctx->policy->rrsig_refresh_before) { + hint->node = node->owner; + hint->rrtype = rrset.type; + hint->warning = KNOT_ESOON_EXPIRE; + assert(until > 0); + hint->remaining_secs = MAX(0, diff); } } else if (sign_ctx->dnssec_ctx->rrsig_drop_existing) { result = force_resign_rrset(&rrset, &rrsigs, sign_ctx, changeset); } else { result = resign_rrset(&rrset, &rrsigs, sign_ctx, skip_crypto, - changeset, expires_at); + changeset); } } @@ -526,7 +540,6 @@ typedef struct { zone_tree_t *tree; zone_sign_ctx_t *sign_ctx; changeset_t changeset; - knot_time_t expires_at; dnssec_validation_hint_t *hint; size_t num_threads; size_t thread_index; @@ -557,11 +570,7 @@ static int sign_node(zone_node_t *node, void *data) return KNOT_EOK; } - int result = sign_node_rrsets(node, args->sign_ctx, - &args->changeset, &args->expires_at, - args->hint); - - return result; + return sign_node_rrsets(node, args->sign_ctx, &args->changeset, args->hint); } static void *tree_sign_thread(void *_arg) @@ -585,7 +594,6 @@ static int set_signed(zone_node_t *node, _unused_ void *data) * \param zone_keys Zone keys. * \param policy DNSSEC policy. * \param update Zone update structure to be updated. - * \param expires_at Expiration time of the oldest signature in zone. * * \return Error code, KNOT_EOK if successful. */ @@ -593,8 +601,7 @@ static int zone_tree_sign(zone_tree_t *tree, size_t num_threads, zone_keyset_t *zone_keys, const kdnssec_ctx_t *dnssec_ctx, - zone_update_t *update, - knot_time_t *expires_at) + zone_update_t *update) { assert(zone_keys || dnssec_ctx->validation_mode); assert(dnssec_ctx); @@ -603,7 +610,6 @@ static int zone_tree_sign(zone_tree_t *tree, int ret = KNOT_EOK; node_sign_args_t args[num_threads]; memset(args, 0, sizeof(args)); - *expires_at = knot_time_plus(dnssec_ctx->now, dnssec_ctx->policy->rrsig_lifetime); // init context structures for (size_t i = 0; i < num_threads; i++) { @@ -619,7 +625,6 @@ static int zone_tree_sign(zone_tree_t *tree, if (ret != KNOT_EOK) { break; } - args[i].expires_at = 0; args[i].hint = &update->validation_hint; args[i].num_threads = num_threads; args[i].thread_index = i; @@ -662,7 +667,6 @@ static int zone_tree_sign(zone_tree_t *tree, ret = args[i].errcode; if (ret == KNOT_EOK && !dnssec_ctx->validation_mode) { ret = zone_update_apply_changeset(update, &args[i].changeset); // _fix not needed - *expires_at = knot_time_min(*expires_at, args[i].expires_at); } } } @@ -701,10 +705,9 @@ static int rrset_add_zone_ds(knot_rrset_t *rrset, zone_key_t *zone_key, dnssec_k int knot_zone_sign(zone_update_t *update, zone_keyset_t *zone_keys, - const kdnssec_ctx_t *dnssec_ctx, - knot_time_t *expire_at) + const kdnssec_ctx_t *dnssec_ctx) { - if (!update || !dnssec_ctx || !expire_at || + if (!update || !dnssec_ctx || dnssec_ctx->policy->signing_threads < 1 || (zone_keys == NULL && !dnssec_ctx->validation_mode)) { return KNOT_EINVAL; @@ -712,16 +715,14 @@ int knot_zone_sign(zone_update_t *update, int result; - knot_time_t normal_expire = 0; result = zone_tree_sign(update->new_cont->nodes, dnssec_ctx->policy->signing_threads, - zone_keys, dnssec_ctx, update, &normal_expire); + zone_keys, dnssec_ctx, update); if (result != KNOT_EOK) { return result; } - knot_time_t nsec3_expire = 0; result = zone_tree_sign(update->new_cont->nsec3_nodes, dnssec_ctx->policy->signing_threads, - zone_keys, dnssec_ctx, update, &nsec3_expire); + zone_keys, dnssec_ctx, update); if (result != KNOT_EOK) { return result; } @@ -732,8 +733,6 @@ int knot_zone_sign(zone_update_t *update, result = zone_tree_apply(whole ? update->new_cont->nsec3_nodes : update->a_ctx->nsec3_ptrs, set_signed, NULL); } - *expire_at = knot_time_min(normal_expire, nsec3_expire); - return result; } @@ -948,7 +947,7 @@ bool knot_zone_sign_use_key(const zone_key_t *key, const knot_rrset_t *covered) } } -static int sign_in_changeset(zone_node_t *node, uint16_t rrtype, knot_rrset_t *rrsigs, +static int sign_in_changeset(zone_node_t *node, uint16_t rrtype, zone_sign_ctx_t *sign_ctx, int ret_prev, bool skip_crypto, zone_update_t *up) { @@ -959,7 +958,8 @@ static int sign_in_changeset(zone_node_t *node, uint16_t rrtype, knot_rrset_t *r if (knot_rrset_empty(&rr)) { return KNOT_EOK; } - return add_missing_rrsigs(&rr, rrsigs, sign_ctx, skip_crypto, NULL, up, NULL); + knot_rrset_t rrsigs = node_rrset(node, KNOT_RRTYPE_RRSIG); + return add_missing_rrsigs(&rr, &rrsigs, sign_ctx, skip_crypto, NULL, up); } int knot_zone_sign_nsecs_in_changeset(const zone_keyset_t *zone_keys, @@ -982,10 +982,9 @@ int knot_zone_sign_nsecs_in_changeset(const zone_keyset_t *zone_keys, zone_node_t *n = zone_tree_it_val(&it); bool skip_crypto = (n->flags & NODE_FLAGS_RRSIGS_VALID) && !dnssec_ctx->keytag_conflict; - knot_rrset_t rrsigs = node_rrset(n, KNOT_RRTYPE_RRSIG); - ret = sign_in_changeset(n, KNOT_RRTYPE_NSEC, &rrsigs, sign_ctx, ret, skip_crypto, update); - ret = sign_in_changeset(n, KNOT_RRTYPE_NSEC3, &rrsigs, sign_ctx, ret, skip_crypto, update); - ret = sign_in_changeset(n, KNOT_RRTYPE_NSEC3PARAM, &rrsigs, sign_ctx, ret, skip_crypto, update); + ret = sign_in_changeset(n, KNOT_RRTYPE_NSEC, sign_ctx, ret, skip_crypto, update); + ret = sign_in_changeset(n, KNOT_RRTYPE_NSEC3, sign_ctx, ret, skip_crypto, update); + ret = sign_in_changeset(n, KNOT_RRTYPE_NSEC3PARAM, sign_ctx, ret, skip_crypto, update); if (ret == KNOT_EOK) { n->flags |= NODE_FLAGS_RRSIGS_VALID; // non-NSEC RRSIGs had been validated in knot_dnssec_sign_update() @@ -1023,10 +1022,9 @@ bool knot_zone_sign_rr_should_be_signed(const zone_node_t *node, int knot_zone_sign_update(zone_update_t *update, zone_keyset_t *zone_keys, - const kdnssec_ctx_t *dnssec_ctx, - knot_time_t *expire_at) + const kdnssec_ctx_t *dnssec_ctx) { - if (update == NULL || dnssec_ctx == NULL || expire_at == NULL || + if (update == NULL || dnssec_ctx == NULL || dnssec_ctx->policy->signing_threads < 1 || (zone_keys == NULL && !dnssec_ctx->validation_mode)) { return KNOT_EINVAL; @@ -1038,16 +1036,16 @@ int knot_zone_sign_update(zone_update_t *update, * If so, we have to sign the whole zone. */ const bool full_sign = apex_dnssec_changed(update); if (full_sign) { - ret = knot_zone_sign(update, zone_keys, dnssec_ctx, expire_at); + ret = knot_zone_sign(update, zone_keys, dnssec_ctx); } else { ret = zone_tree_sign(update->a_ctx->node_ptrs, dnssec_ctx->policy->signing_threads, - zone_keys, dnssec_ctx, update, expire_at); + zone_keys, dnssec_ctx, update); if (ret == KNOT_EOK) { ret = zone_tree_apply(update->a_ctx->node_ptrs, set_signed, NULL); } if (ret == KNOT_EOK && dnssec_ctx->validation_mode) { ret = zone_tree_sign(update->a_ctx->nsec3_ptrs, dnssec_ctx->policy->signing_threads, - zone_keys, dnssec_ctx, update, expire_at); + zone_keys, dnssec_ctx, update); } if (ret == KNOT_EOK && dnssec_ctx->validation_mode) { ret = zone_tree_apply(update->a_ctx->nsec3_ptrs, set_signed, NULL); diff --git a/src/knot/dnssec/zone-sign.h b/src/knot/dnssec/zone-sign.h index ba6e2b2..480bcf9 100644 --- a/src/knot/dnssec/zone-sign.h +++ b/src/knot/dnssec/zone-sign.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -81,13 +81,15 @@ keyptr_dynarray_t knot_zone_sign_get_cdnskeys(const kdnssec_ctx_t *ctx, * \param rrsigs RRSIG with signatures. * \param sign_ctx Signing context (with keys == NULL) * \param skip_crypto Crypto operations might be skipped as they had been successful earlier. + * \param valid_until End of soonest RRSIG validity. * * \return KNOT_E* */ int knot_validate_rrsigs(const knot_rrset_t *covered, const knot_rrset_t *rrsigs, zone_sign_ctx_t *sign_ctx, - bool skip_crypto); + bool skip_crypto, + knot_time_t *valid_until); /*! * \brief Update zone signatures and store performed changes in update. @@ -97,14 +99,12 @@ int knot_validate_rrsigs(const knot_rrset_t *covered, * \param update Zone Update containing the zone and to be updated with new DNSKEYs and RRSIGs. * \param zone_keys Zone keys. * \param dnssec_ctx DNSSEC context. - * \param expire_at Time, when the oldest signature in the zone expires. * * \return Error code, KNOT_EOK if successful. */ int knot_zone_sign(zone_update_t *update, zone_keyset_t *zone_keys, - const kdnssec_ctx_t *dnssec_ctx, - knot_time_t *expire_at); + const kdnssec_ctx_t *dnssec_ctx); /*! * \brief Sign NSEC/NSEC3 nodes in changeset and update the changeset. @@ -138,14 +138,12 @@ bool knot_zone_sign_rr_should_be_signed(const zone_node_t *node, * \param update Zone Update structure. * \param zone_keys Zone keys. * \param dnssec_ctx DNSSEC context. - * \param expire_at Time, when the oldest signature in the update expires. * * \return Error code, KNOT_EOK if successful. */ int knot_zone_sign_update(zone_update_t *update, zone_keyset_t *zone_keys, - const kdnssec_ctx_t *dnssec_ctx, - knot_time_t *expire_at); + const kdnssec_ctx_t *dnssec_ctx); /*! * \brief Force re-sign of a RRSet in zone apex. diff --git a/src/knot/events/events.c b/src/knot/events/events.c index f0de68e..6224006 100644 --- a/src/knot/events/events.c +++ b/src/knot/events/events.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -46,6 +46,7 @@ static const event_info_t EVENT_INFO[] = { { ZONE_EVENT_BACKUP, event_backup, "backup/restore" }, { ZONE_EVENT_NOTIFY, event_notify, "notify" }, { ZONE_EVENT_DNSSEC, event_dnssec, "re-sign" }, + { ZONE_EVENT_VALIDATE, event_validate, "DNSSEC-validate" }, { ZONE_EVENT_UFREEZE, event_ufreeze, "update-freeze" }, { ZONE_EVENT_UTHAW, event_uthaw, "update-thaw" }, { ZONE_EVENT_DS_CHECK, event_ds_check, "DS-check" }, diff --git a/src/knot/events/events.h b/src/knot/events/events.h index a32d195..cf1b362 100644 --- a/src/knot/events/events.h +++ b/src/knot/events/events.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -38,6 +38,7 @@ typedef enum zone_event_type { ZONE_EVENT_BACKUP, ZONE_EVENT_NOTIFY, ZONE_EVENT_DNSSEC, + ZONE_EVENT_VALIDATE, ZONE_EVENT_UFREEZE, ZONE_EVENT_UTHAW, ZONE_EVENT_DS_CHECK, diff --git a/src/knot/events/handlers.h b/src/knot/events/handlers.h index d74fd8a..45b7b45 100644 --- a/src/knot/events/handlers.h +++ b/src/knot/events/handlers.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -39,6 +39,8 @@ int event_dnssec(conf_t *conf, zone_t *zone); /*! \brief NOT A HANDLER, just a helper function to reschedule based on reschedule_t */ void event_dnssec_reschedule(conf_t *conf, zone_t *zone, const zone_sign_reschedule_t *refresh, bool zone_changed); +/*! \brief Validate the wole zone's DNSSEC. */ +int event_validate(conf_t *conf, zone_t *zone); /*! \brief Freeze those events causing zone contents change. */ int event_ufreeze(conf_t *conf, zone_t *zone); /*! \brief Unfreeze zone updates. */ diff --git a/src/knot/events/handlers/dnskey_sync.c b/src/knot/events/handlers/dnskey_sync.c index c6d80ff..018f66b 100644 --- a/src/knot/events/handlers/dnskey_sync.c +++ b/src/knot/events/handlers/dnskey_sync.c @@ -26,8 +26,8 @@ #define DNSKEY_SYNC_LOG(priority, zone, remote, flags, fmt, ...) \ ns_log(priority, zone, LOG_OPERATION_DNSKEY_SYNC, LOG_DIRECTION_OUT, &(remote)->addr, \ - ((flags) & KNOT_REQUESTOR_QUIC) ? KNOTD_QUERY_PROTO_QUIC : KNOTD_QUERY_PROTO_TCP, \ - ((flags) & KNOT_REQUESTOR_REUSED), (remote)->key.name, fmt, ## __VA_ARGS__) + flags2proto(flags), ((flags) & KNOT_REQUESTOR_REUSED), (remote)->key.name, \ + fmt, ## __VA_ARGS__) static const unsigned remote_rrs[] = { KNOT_RRTYPE_DNSKEY, KNOT_RRTYPE_CDNSKEY, KNOT_RRTYPE_CDS }; #define REMOTE_NTYPES (sizeof(remote_rrs) / sizeof(remote_rrs[0])) diff --git a/src/knot/events/handlers/ds_push.c b/src/knot/events/handlers/ds_push.c index be7621f..761b800 100644 --- a/src/knot/events/handlers/ds_push.c +++ b/src/knot/events/handlers/ds_push.c @@ -38,8 +38,8 @@ struct ds_push_data { #define DS_PUSH_LOG(priority, zone, remote, flags, fmt, ...) \ ns_log(priority, zone, LOG_OPERATION_DS_PUSH, LOG_DIRECTION_OUT, &(remote)->addr, \ - ((flags) & KNOT_REQUESTOR_QUIC) ? KNOTD_QUERY_PROTO_QUIC : KNOTD_QUERY_PROTO_TCP, \ - ((flags) & KNOT_REQUESTOR_REUSED), (remote)->key.name, fmt, ## __VA_ARGS__) + flags2proto(flags), ((flags) & KNOT_REQUESTOR_REUSED), (remote)->key.name, \ + fmt, ## __VA_ARGS__) static const knot_rdata_t remove_cds = { 5, { 0, 0, 0, 0, 0 } }; @@ -53,7 +53,7 @@ static int ds_push_begin(knot_layer_t *layer, void *params) static int parent_soa_produce(struct ds_push_data *data, knot_pkt_t *pkt) { assert(data->parent_query[0] != '\0'); - data->parent_query = knot_wire_next_label(data->parent_query, NULL); + data->parent_query = knot_dname_next_label(data->parent_query); int ret = knot_pkt_put_question(pkt, data->parent_query, KNOT_CLASS_IN, KNOT_RRTYPE_SOA); if (ret != KNOT_EOK) { diff --git a/src/knot/events/handlers/notify.c b/src/knot/events/handlers/notify.c index 9dae70a..9a8b8df 100644 --- a/src/knot/events/handlers/notify.c +++ b/src/knot/events/handlers/notify.c @@ -84,8 +84,8 @@ static const knot_layer_api_t NOTIFY_API = { #define NOTIFY_OUT_LOG(priority, zone, remote, flags, fmt, ...) \ ns_log(priority, zone, LOG_OPERATION_NOTIFY, LOG_DIRECTION_OUT, &(remote)->addr, \ - ((flags) & KNOT_REQUESTOR_QUIC) ? KNOTD_QUERY_PROTO_QUIC : KNOTD_QUERY_PROTO_TCP, \ - ((flags) & KNOT_REQUESTOR_REUSED), (remote)->key.name, fmt, ## __VA_ARGS__) + flags2proto(flags), ((flags) & KNOT_REQUESTOR_REUSED), (remote)->key.name, \ + fmt, ## __VA_ARGS__) static int send_notify(conf_t *conf, zone_t *zone, const knot_rrset_t *soa, const conf_remote_t *slave, int timeout, bool retry) diff --git a/src/knot/events/handlers/refresh.c b/src/knot/events/handlers/refresh.c index 8099df6..6c22707 100644 --- a/src/knot/events/handlers/refresh.c +++ b/src/knot/events/handlers/refresh.c @@ -68,24 +68,24 @@ * \endverbatim */ -#define PROTO(data) \ - ((data)->layer->flags & KNOT_REQUESTOR_QUIC) ? KNOTD_QUERY_PROTO_QUIC : KNOTD_QUERY_PROTO_TCP - #define REFRESH_LOG(priority, data, msg...) \ ns_log(priority, (data)->zone->name, LOG_OPERATION_REFRESH, LOG_DIRECTION_NONE, \ &(data)->remote->addr, 0, false, (data)->remote->key.name, msg) #define REFRESH_LOG_PROTO(priority, data, msg...) \ ns_log(priority, (data)->zone->name, LOG_OPERATION_REFRESH, LOG_DIRECTION_NONE, \ - &(data)->remote->addr, PROTO(data), (data)->layer->flags & KNOT_REQUESTOR_REUSED, (data)->remote->key.name, msg) + &(data)->remote->addr, flags2proto((data)->layer->flags), \ + (data)->layer->flags & KNOT_REQUESTOR_REUSED, (data)->remote->key.name, msg) #define AXFRIN_LOG(priority, data, msg...) \ ns_log(priority, (data)->zone->name, LOG_OPERATION_AXFR, LOG_DIRECTION_IN, \ - &(data)->remote->addr, PROTO(data), (data)->layer->flags & KNOT_REQUESTOR_REUSED, (data)->remote->key.name, msg) + &(data)->remote->addr, flags2proto((data)->layer->flags), \ + (data)->layer->flags & KNOT_REQUESTOR_REUSED, (data)->remote->key.name, msg) #define IXFRIN_LOG(priority, data, msg...) \ ns_log(priority, (data)->zone->name, LOG_OPERATION_IXFR, LOG_DIRECTION_IN, \ - &(data)->remote->addr, PROTO(data), (data)->layer->flags & KNOT_REQUESTOR_REUSED, (data)->remote->key.name, msg) + &(data)->remote->addr, flags2proto((data)->layer->flags), \ + (data)->layer->flags & KNOT_REQUESTOR_REUSED, (data)->remote->key.name, msg) enum state { REFRESH_STATE_INVALID = 0, @@ -123,7 +123,7 @@ struct refresh_data { int ret; //!< Error code. enum state state; //!< Event processing state. - enum xfr_type xfr_type; //!< Transer type (mostly IXFR versus AXFR). + enum xfr_type xfr_type; //!< Transfer type (mostly IXFR versus AXFR). bool axfr_style_ixfr; //!< Master responded with AXFR-style-IXFR. knot_rrset_t *initial_soa_copy; //!< Copy of the received initial SOA. struct xfr_stats stats; //!< Transfer statistics. @@ -1200,14 +1200,33 @@ static int transfer_consume(knot_layer_t *layer, knot_pkt_t *pkt) // Transfer completed if (next == KNOT_STATE_DONE) { // Log transfer even if we still can fail + uint32_t serial; + switch (data->xfr_type) { + case XFR_TYPE_AXFR: + serial = zone_contents_serial(data->axfr.zone); + break; + case XFR_TYPE_IXFR: + serial = knot_soa_serial(data->ixfr.final_soa->rrs.rdata); + break; + case XFR_TYPE_UPTODATE: + if (slave_zone_serial(data->zone, data->conf, &serial) == KNOT_EOK) { + break; + } + // FALLTHROUGH + default: + serial = 0; + } + char serial_log[32]; + (void)snprintf(serial_log, sizeof(serial_log), + " remote serial %u,", serial); xfr_log_finished(data->zone->name, data->xfr_type == XFR_TYPE_IXFR || data->xfr_type == XFR_TYPE_UPTODATE ? LOG_OPERATION_IXFR : LOG_OPERATION_AXFR, LOG_DIRECTION_IN, &data->remote->addr, - (layer->flags & KNOT_REQUESTOR_QUIC ? - KNOTD_QUERY_PROTO_QUIC : KNOTD_QUERY_PROTO_TCP), - data->remote->key.name, &data->stats); + flags2proto(layer->flags), + data->remote->key.name, + serial_log, &data->stats); /* * TODO: Move finialization into finish diff --git a/src/knot/events/handlers/update.c b/src/knot/events/handlers/update.c index b4092a3..2c6758c 100644 --- a/src/knot/events/handlers/update.c +++ b/src/knot/events/handlers/update.c @@ -28,6 +28,9 @@ #include "knot/zone/zone.h" #include "libdnssec/random.h" #include "libknot/libknot.h" +#include "libknot/quic/quic_conn.h" +#include "libknot/quic/quic.h" +#include "libknot/quic/tls.h" #include "contrib/net.h" #include "contrib/time.h" @@ -51,6 +54,33 @@ static void init_qdata_from_request(knotd_qdata_t *qdata, qdata->extra->zone = zone; } +#ifdef ENABLE_QUIC +static int ddnsq_alloc_reply(knot_quic_reply_t *r) +{ + r->out_payload->iov_len = KNOT_WIRE_MAX_PKTSIZE; + + return KNOT_EOK; +} + +static int ddnsq_send_reply(knot_quic_reply_t *r) +{ + int fd = *(int *)r->sock; + int ret = net_dgram_send(fd, r->out_payload->iov_base, r->out_payload->iov_len, r->ip_rem); + if (ret < 0) { + return knot_map_errno(); + } else if (ret == r->out_payload->iov_len) { + return KNOT_EOK; + } else { + return KNOT_EAGAIN; + } +} + +static void ddnsq_free_reply(knot_quic_reply_t *r) +{ + r->out_payload->iov_len = 0; +} +#endif // ENABLE_QUIC + static int check_prereqs(knot_request_t *request, zone_update_t *update, knotd_qdata_t *qdata) @@ -65,6 +95,15 @@ static int check_prereqs(knot_request_t *request, return ret; } + ret = ddns_precheck_update(request->query, update, &rcode); + if (ret != KNOT_EOK) { + UPDATE_LOG(LOG_WARNING, qdata, "broken update format (%s)", + knot_strerror(ret)); + assert(rcode != KNOT_RCODE_NOERROR); + knot_wire_set_rcode(request->resp->wire, rcode); + return ret; + } + return KNOT_EOK; } @@ -104,6 +143,7 @@ static int process_bulk(zone_t *zone, list_t *requests, zone_update_t *up) knot_request_t *req = node->d; // Init qdata structure for logging (unique per-request). knotd_qdata_params_t params = { + .proto = flags2proto(req->flags), .remote = &req->remote }; knotd_qdata_t qdata; @@ -118,6 +158,8 @@ static int process_bulk(zone_t *zone, list_t *requests, zone_update_t *up) ret = process_single_update(req, up, &qdata); if (ret != KNOT_EOK) { + log_zone_error(zone->name, "DDNS, dropping %zu updates in a bulk", + list_size(requests)); return ret; } } @@ -338,6 +380,39 @@ static void send_update_response(conf_t *conf, zone_t *zone, knot_request_t *req (void)process_query_sign_response(req->resp, &qdata); } + if (net_is_stream(req->fd) && req->tls_req_ctx.conn != NULL) { + (void)knot_tls_send_dns(req->tls_req_ctx.conn, + req->resp->wire, req->resp->size); + knot_tls_conn_block(req->tls_req_ctx.conn, false); + } +#ifdef ENABLE_QUIC + else if (req->quic_conn != NULL) { + assert(!net_is_stream(req->fd)); + uint8_t op_buf[KNOT_WIRE_MAX_PKTSIZE]; + struct iovec out_payload = { .iov_base = op_buf, .iov_len = sizeof(op_buf) }; + knot_quic_reply_t rpl = { + .ip_rem = &req->remote, + .ip_loc = &req->source, + .in_payload = NULL, + .out_payload = &out_payload, + .sock = &req->fd, + .alloc_reply = ddnsq_alloc_reply, + .send_reply = ddnsq_send_reply, + .free_reply = ddnsq_free_reply + }; + + void *succ = knot_quic_stream_add_data(req->quic_conn, req->quic_stream, + req->resp->wire, req->resp->size); + if (succ != NULL) { // else ENOMEM + (void)knot_quic_send(req->quic_conn->quic_table, req->quic_conn, + &rpl, 4, KNOT_QUIC_SEND_IGNORE_BLOCKED); + } + knot_quic_conn_block(req->quic_conn, false); + } else // NOTE ties to 'if' below +#else + assert(req->quic_conn == NULL); +#endif // ENABLE_QUIC + if (net_is_stream(req->fd)) { net_dns_tcp_send(req->fd, req->resp->wire, req->resp->size, conf->cache.srv_tcp_remote_io_timeout, NULL); @@ -348,22 +423,13 @@ static void send_update_response(conf_t *conf, zone_t *zone, knot_request_t *req } } -static void free_request(knot_request_t *req) -{ - close(req->fd); - knot_pkt_free(req->query); - knot_pkt_free(req->resp); - dnssec_binary_free(&req->sign.tsig_key.secret); - free(req); -} - static void send_update_responses(conf_t *conf, zone_t *zone, list_t *updates) { ptrnode_t *node, *nxt; WALK_LIST_DELSAFE(node, nxt, *updates) { knot_request_t *req = node->d; send_update_response(conf, zone, req); - free_request(req); + knot_request_free(req, NULL); } ptrlist_free(updates, NULL); } diff --git a/src/knot/events/handlers/validate.c b/src/knot/events/handlers/validate.c new file mode 100644 index 0000000..e410b4f --- /dev/null +++ b/src/knot/events/handlers/validate.c @@ -0,0 +1,34 @@ +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + 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 3 of the License, 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 <https://www.gnu.org/licenses/>. + */ + +#include "knot/common/log.h" +#include "knot/conf/conf.h" +#include "knot/dnssec/zone-events.h" +#include "knot/zone/zone.h" + +int event_validate(conf_t *conf, zone_t *zone) +{ + knot_time_t now = knot_time(); + zone_update_t fake_upd = { + .zone = zone, + .new_cont = zone->contents, + // .validation_hint is zeroed + }; + + log_zone_info(zone->name, "DNSSEC, re-validating zone fully"); + + return knot_dnssec_validate_zone(&fake_upd, conf, now, false, true); +} diff --git a/src/knot/events/replan.c b/src/knot/events/replan.c index ed03fe1..29a07ea 100644 --- a/src/knot/events/replan.c +++ b/src/knot/events/replan.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -108,6 +108,9 @@ void replan_from_timers(conf_t *conf, zone_t *zone) if (zone->contents == NULL && zone->timers.last_refresh_ok) { // zone disappeared w/o expiry refresh = now; } + if (refresh == 0) { // sanitize in case of concurrent purge event + refresh = now; + } assert(refresh > 0); } diff --git a/src/knot/include/module.h b/src/knot/include/module.h index 15a9077..9998e48 100644 --- a/src/knot/include/module.h +++ b/src/knot/include/module.h @@ -36,7 +36,7 @@ /*** Query module API. ***/ /*! Current module ABI version. */ -#define KNOTD_MOD_ABI_VERSION 500 +#define KNOTD_MOD_ABI_VERSION 600 /*! Module configuration name prefix. */ #define KNOTD_MOD_NAME_PREFIX "mod-" @@ -354,7 +354,7 @@ knotd_conf_t knotd_conf_check_item(knotd_conf_check_args_t *args, const yp_name_t *item_name); /*! - * \brief Checks if address is in at least one of given ranges. + * Checks if address is in at least one of given ranges. * * \param[in] range * \param[in] addr @@ -393,11 +393,13 @@ typedef enum { KNOTD_QUERY_PROTO_UDP = KNOT_PROBE_PROTO_UDP, /*!< Pure UDP. */ KNOTD_QUERY_PROTO_TCP = KNOT_PROBE_PROTO_TCP, /*!< Pure TCP. */ KNOTD_QUERY_PROTO_QUIC = KNOT_PROBE_PROTO_QUIC, /*!< QUIC/UDP. */ + KNOTD_QUERY_PROTO_TLS = KNOT_PROBE_PROTO_TLS, /*!< TLS/TCP. */ } knotd_query_proto_t; /*! Query processing specific flags. */ typedef enum { - KNOTD_QUERY_FLAG_COOKIE = 1 << 0, /*!< Valid DNS Cookie indication. */ + KNOTD_QUERY_FLAG_COOKIE = 1 << 0, /*!< Valid DNS Cookie indication. */ + KNOTD_QUERY_FLAG_AUTHORIZED = 1 << 1, /*!< Successfully authorized operation. */ } knotd_query_flag_t; /*! Query processing data context parameters. */ @@ -411,6 +413,7 @@ typedef struct { void *server; /*!< Server object private item. */ const struct knot_xdp_msg *xdp_msg; /*!< Possible XDP message context. */ struct knot_quic_conn *quic_conn; /*!< QUIC connection context. */ + struct knot_tls_conn *tls_conn; /*!< TLS connection context. */ int64_t quic_stream; /*!< QUIC stream ID inside quic_conn. */ uint32_t measured_rtt; /*!< Measured RTT in usecs: QUIC or TCP-XDP. */ } knotd_qdata_params_t; @@ -493,6 +496,7 @@ knot_rrset_t knotd_qdata_zone_apex_rrset(const knotd_qdata_t *qdata, uint16_t ty * \param[in] qdata Query data. * \param[in] zone_name Optional zone name, the current one otherwise. * \param[in] node_name Optional node name, apex otherwise. + * \param[in] type RRSet type. * \param[out] out Destination rrset to store the output to. * * \return Error code (KNOT_ENOZONE, KNOT_EEMPTYZONE, KNOT_ENONODE), KNOT_EOK if success. @@ -501,6 +505,12 @@ int knotd_qdata_zone_rrset(const knotd_qdata_t *qdata, const knot_dname_t *zone_ const knot_dname_t *node_name, uint16_t type, knot_rrset_t *out); +/*! Transport protocol processing states. */ +typedef enum { + KNOTD_PROTO_STATE_PASS = 0, /*!< Process normally. */ + KNOTD_PROTO_STATE_BLOCK = 1, /*!< Block the packet/connection. */ +} knotd_proto_state_t; + /*! General query processing states. */ typedef enum { KNOTD_STATE_NOOP = 0, /*!< No response. */ @@ -509,7 +519,7 @@ typedef enum { KNOTD_STATE_FINAL = 6, /*!< Finished and finalized (QNAME, EDNS, TSIG). */ } knotd_state_t; -/*! brief Internet query processing states. */ +/*! Internet query processing states. */ typedef enum { KNOTD_IN_STATE_BEGIN, /*!< Begin name resolution. */ KNOTD_IN_STATE_NODATA, /*!< Positive result with NO data. */ @@ -523,15 +533,29 @@ typedef enum { /*! Query module processing stages. */ typedef enum { - KNOTD_STAGE_BEGIN = 0, /*!< Before query processing. */ - KNOTD_STAGE_PREANSWER, /*!< Before section processing. */ - KNOTD_STAGE_ANSWER, /*!< Answer section processing. */ - KNOTD_STAGE_AUTHORITY, /*!< Authority section processing. */ - KNOTD_STAGE_ADDITIONAL, /*!< Additional section processing. */ - KNOTD_STAGE_END, /*!< After query processing. */ + KNOTD_STAGE_PROTO_BEGIN = 0, /*!< Start of transport protocol processing. */ + KNOTD_STAGE_BEGIN, /*!< Before query processing. */ + KNOTD_STAGE_PREANSWER, /*!< Before section processing. */ + KNOTD_STAGE_ANSWER, /*!< Answer section processing. */ + KNOTD_STAGE_AUTHORITY, /*!< Authority section processing. */ + KNOTD_STAGE_ADDITIONAL, /*!< Additional section processing. */ + KNOTD_STAGE_END, /*!< After query processing. */ + KNOTD_STAGE_PROTO_END, /*!< End of transport protocol processing. */ } knotd_stage_t; /*! + * Transport protocol processing hook. + * + * \param[in] state Current processing state. + * \param[in] params Processing parameters. + * \param[in] mod Module context. + * + * \return Next processing state. + */ +typedef knotd_proto_state_t (*knotd_mod_proto_hook_f) + (knotd_proto_state_t state, knotd_qdata_params_t *params, knotd_mod_t *mod); + +/*! * General processing hook. * * \param[in] state Current processing state. @@ -558,6 +582,17 @@ typedef knotd_in_state_t (*knotd_mod_in_hook_f) (knotd_in_state_t state, knot_pkt_t *pkt, knotd_qdata_t *qdata, knotd_mod_t *mod); /*! + * Registers transport protocol processing module hook. + * + * \param[in] mod Module context. + * \param[in] stage Processing stage (KNOTD_STAGE_PROTO_BEGIN or KNOTD_STAGE_PROTO_END). + * \param[in] hook Module hook. + * + * \return Error code, KNOT_EOK if success. + */ +int knotd_mod_proto_hook(knotd_mod_t *mod, knotd_stage_t stage, knotd_mod_proto_hook_f hook); + +/*! * Registers general processing module hook. * * \param[in] mod Module context. diff --git a/src/knot/modules/cookies/cookies.c b/src/knot/modules/cookies/cookies.c index 34c4b22..48eca7d 100644 --- a/src/knot/modules/cookies/cookies.c +++ b/src/knot/modules/cookies/cookies.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -20,19 +20,10 @@ #include "knot/include/module.h" #include "libknot/libknot.h" +#include "contrib/atomic.h" #include "contrib/string.h" #include "libdnssec/random.h" -#ifdef HAVE_ATOMIC -#define ATOMIC_SET(dst, val) __atomic_store_n(&(dst), (val), __ATOMIC_RELAXED) -#define ATOMIC_GET(src) __atomic_load_n(&(src), __ATOMIC_RELAXED) -#define ATOMIC_ADD(dst, val) __atomic_add_fetch(&(dst), (val), __ATOMIC_RELAXED) -#else -#define ATOMIC_SET(dst, val) ((dst) = (val)) -#define ATOMIC_GET(src) (src) -#define ATOMIC_ADD(dst, val) ((dst) += (val)) -#endif - #define BADCOOKIE_CTR_INIT 1 #define MOD_SECRET_LIFETIME "\x0F""secret-lifetime" @@ -59,13 +50,13 @@ int cookies_conf_check(knotd_conf_check_args_t *args) typedef struct { struct { - uint64_t variable; + knot_atomic_uint64_t variable; uint64_t constant; } secret; pthread_t update_secret; uint32_t secret_lifetime; uint32_t badcookie_slip; - uint16_t badcookie_ctr; // Counter for BADCOOKIE answers. + knot_atomic_uint16_t badcookie_ctr; // Counter for BADCOOKIE answers. } cookies_ctx_t; static void update_ctr(cookies_ctx_t *ctx) @@ -285,7 +276,7 @@ int cookies_load(knotd_mod_t *mod) } } -#ifndef HAVE_ATOMIC +#ifndef KNOT_HAVE_ATOMIC knotd_mod_log(mod, LOG_WARNING, "the module might work slightly wrong on this platform"); ctx->badcookie_slip = 1; #endif diff --git a/src/knot/modules/probe/probe.c b/src/knot/modules/probe/probe.c index 9207308..3e0a646 100644 --- a/src/knot/modules/probe/probe.c +++ b/src/knot/modules/probe/probe.c @@ -19,18 +19,11 @@ #include "knot/conf/schema.h" #include "knot/include/module.h" +#include "contrib/atomic.h" #include "contrib/string.h" #include "contrib/time.h" #include "libknot/libknot.h" -#ifdef HAVE_ATOMIC -#define ATOMIC_SET(dst, val) __atomic_store_n(&(dst), (val), __ATOMIC_RELAXED) -#define ATOMIC_GET(src) __atomic_load_n(&(src), __ATOMIC_RELAXED) -#else -#define ATOMIC_SET(dst, val) ((dst) = (val)) -#define ATOMIC_GET(src) (src) -#endif - #define MOD_PATH "\x04""path" #define MOD_CHANNELS "\x08""channels" #define MOD_MAX_RATE "\x08""max-rate" @@ -45,7 +38,7 @@ const yp_item_t probe_conf[] = { typedef struct { knot_probe_t **probes; size_t probe_count; - uint64_t *last_times; + knot_atomic_uint64_t *last_times; uint64_t min_diff_ns; char *path; } probe_ctx_t; @@ -139,7 +132,7 @@ int probe_load(knotd_mod_t *mod) return KNOT_ENOMEM; } - ctx->last_times = calloc(ctx->probe_count, sizeof(uint64_t)); + ctx->last_times = calloc(ctx->probe_count, sizeof(*ctx->last_times)); if (ctx->last_times == NULL) { free_probe_ctx(ctx); return KNOT_ENOMEM; diff --git a/src/knot/modules/rrl/Makefile.inc b/src/knot/modules/rrl/Makefile.inc index d82edf9..fbb9eb0 100644 --- a/src/knot/modules/rrl/Makefile.inc +++ b/src/knot/modules/rrl/Makefile.inc @@ -1,15 +1,20 @@ knot_modules_rrl_la_SOURCES = knot/modules/rrl/rrl.c \ knot/modules/rrl/functions.c \ - knot/modules/rrl/functions.h + knot/modules/rrl/functions.h \ + knot/modules/rrl/kru-generic.c \ + knot/modules/rrl/kru-avx2.c \ + knot/modules/rrl/kru.h +noinst_HEADERS = knot/modules/rrl/kru.inc.c EXTRA_DIST += knot/modules/rrl/rrl.rst if STATIC_MODULE_rrl libknotd_la_SOURCES += $(knot_modules_rrl_la_SOURCES) +libknotd_la_LIBADD += $(math_LIBS) endif if SHARED_MODULE_rrl knot_modules_rrl_la_LDFLAGS = $(KNOTD_MOD_LDFLAGS) knot_modules_rrl_la_CPPFLAGS = $(KNOTD_MOD_CPPFLAGS) -knot_modules_rrl_la_LIBADD = $(libcontrib_LIBS) +knot_modules_rrl_la_LIBADD = $(libcontrib_LIBS) $(math_LIBS) pkglib_LTLIBRARIES += knot/modules/rrl.la endif diff --git a/src/knot/modules/rrl/functions.c b/src/knot/modules/rrl/functions.c index df35394..01d89cb 100644 --- a/src/knot/modules/rrl/functions.c +++ b/src/knot/modules/rrl/functions.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -14,516 +14,223 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. */ -#include <assert.h> +#include <stdatomic.h> #include <time.h> #include "knot/modules/rrl/functions.h" +#include "knot/modules/rrl/kru.h" +#include "contrib/macros.h" #include "contrib/musl/inet_ntop.h" -#include "contrib/openbsd/strlcat.h" #include "contrib/sockaddr.h" #include "contrib/time.h" -#include "libdnssec/error.h" #include "libdnssec/random.h" -/* Hopscotch defines. */ -#define HOP_LEN (sizeof(unsigned)*8) -/* Limits (class, ipv6 remote, dname) */ -#define RRL_CLSBLK_MAXLEN (1 + 8 + 255) -/* CIDR block prefix lengths for v4/v6 */ -#define RRL_V4_PREFIX_LEN 3 /* /24 */ -#define RRL_V6_PREFIX_LEN 7 /* /56 */ -/* Defaults */ -#define RRL_SSTART 2 /* 1/Nth of the rate for slow start */ -#define RRL_PSIZE_LARGE 1024 -#define RRL_CAPACITY 4 /* Window size in seconds */ -#define RRL_LOCK_GRANULARITY 32 /* Last digit granularity */ - -/* Classification */ -enum { - CLS_NULL = 0 << 0, /* Empty bucket. */ - CLS_NORMAL = 1 << 0, /* Normal response. */ - CLS_ERROR = 1 << 1, /* Error response. */ - CLS_NXDOMAIN = 1 << 2, /* NXDOMAIN (special case of error). */ - CLS_EMPTY = 1 << 3, /* Empty response. */ - CLS_LARGE = 1 << 4, /* Response size over threshold (1024k). */ - CLS_WILDCARD = 1 << 5, /* Wildcard query. */ - CLS_ANY = 1 << 6, /* ANY query (spec. class). */ - CLS_DNSSEC = 1 << 7 /* DNSSEC related RR query (spec. class) */ -}; +// CIDR block prefix lengths for v4/v6 (hardcoded also in unit tests). +#define RRL_V4_PREFIXES (uint8_t[]) { 18, 20, 24, 32 } +#define RRL_V4_RATE_MULT (kru_price_t[]) { 768, 256, 32, 1 } -/* Classification string. */ -struct cls_name { - int code; - const char *name; -}; +#define RRL_V6_PREFIXES (uint8_t[]) { 32, 48, 56, 64, 128 } +#define RRL_V6_RATE_MULT (kru_price_t[]) { 64, 4, 3, 2, 1 } -static const struct cls_name rrl_cls_names[] = { - { CLS_NORMAL, "POSITIVE" }, - { CLS_ERROR, "ERROR" }, - { CLS_NXDOMAIN, "NXDOMAIN"}, - { CLS_EMPTY, "EMPTY"}, - { CLS_LARGE, "LARGE"}, - { CLS_WILDCARD, "WILDCARD"}, - { CLS_ANY, "ANY"}, - { CLS_DNSSEC, "DNSSEC"}, - { CLS_NULL, "NULL"}, - { CLS_NULL, NULL} -}; +#define RRL_V4_PREFIXES_CNT (sizeof(RRL_V4_PREFIXES) / sizeof(*RRL_V4_PREFIXES)) +#define RRL_V6_PREFIXES_CNT (sizeof(RRL_V6_PREFIXES) / sizeof(*RRL_V6_PREFIXES)) +#define RRL_MAX_PREFIXES_CNT ((RRL_V4_PREFIXES_CNT > RRL_V6_PREFIXES_CNT) ? RRL_V4_PREFIXES_CNT : RRL_V6_PREFIXES_CNT) -static inline const char *rrl_clsstr(int code) -{ - for (const struct cls_name *c = rrl_cls_names; c->name; c++) { - if (c->code == code) { - return c->name; - } - } +#ifndef CLOCK_MONOTONIC_COARSE +#define CLOCK_MONOTONIC_COARSE CLOCK_MONOTONIC +#endif - return "unknown class"; -} +#define RRL_LIMIT_KOEF 1/2 // Avoid probabilistic rounding wherever possible. -/* Bucket flags. */ -enum { - RRL_BF_NULL = 0 << 0, /* No flags. */ - RRL_BF_SSTART = 1 << 0, /* Bucket in slow-start after collision. */ - RRL_BF_ELIMIT = 1 << 1 /* Bucket is rate-limited. */ +struct rrl_table { + kru_price_t v4_prices[RRL_V4_PREFIXES_CNT]; + kru_price_t v6_prices[RRL_V6_PREFIXES_CNT]; + uint32_t log_period; + bool rw_mode; + _Atomic uint32_t log_time; + _Alignas(64) uint8_t kru[]; }; -static uint8_t rrl_clsid(rrl_req_t *p) -{ - /* Check error code */ - int ret = CLS_NULL; - switch (knot_wire_get_rcode(p->wire)) { - case KNOT_RCODE_NOERROR: ret = CLS_NORMAL; break; - case KNOT_RCODE_NXDOMAIN: return CLS_NXDOMAIN; break; - default: return CLS_ERROR; break; - } - - /* Check if answered from a qname */ - if (ret == CLS_NORMAL && p->flags & RRL_REQ_WILDCARD) { - return CLS_WILDCARD; - } - - /* Check query type for spec. classes. */ - if (p->query) { - switch(knot_pkt_qtype(p->query)) { - case KNOT_RRTYPE_ANY: /* ANY spec. class */ - return CLS_ANY; - break; - case KNOT_RRTYPE_DNSKEY: - case KNOT_RRTYPE_RRSIG: - case KNOT_RRTYPE_DS: /* DNSSEC-related RR class. */ - return CLS_DNSSEC; - break; - default: - break; - } - } - - /* Check packet size for threshold. */ - if (p->len >= RRL_PSIZE_LARGE) { - return CLS_LARGE; - } - - /* Check ancount */ - if (knot_wire_get_ancount(p->wire) == 0) { - return CLS_EMPTY; - } - - return ret; -} - -static int rrl_clsname(uint8_t *dst, size_t maxlen, uint8_t cls, rrl_req_t *req, - const knot_dname_t *name) +static void addr_tostr(char *dst, size_t maxlen, const struct sockaddr_storage *ss) { - if (name == NULL) { - /* Fallback for errors etc. */ - name = (const knot_dname_t *)"\x00"; - } - - switch (cls) { - case CLS_ERROR: /* Could be a non-existent zone or garbage. */ - case CLS_NXDOMAIN: /* Queries to non-existent names in zone. */ - case CLS_WILDCARD: /* Queries to names covered by a wildcard. */ - break; - default: - /* Use QNAME */ - if (req->query) { - name = knot_pkt_qname(req->query); - } - break; - } + assert(ss); - /* Write to wire */ - return knot_dname_to_wire(dst, name, maxlen); -} - -static int rrl_classify(uint8_t *dst, size_t maxlen, const struct sockaddr_storage *remote, - rrl_req_t *req, const knot_dname_t *name) -{ - /* Class */ - uint8_t cls = rrl_clsid(req); - *dst = cls; - int blklen = sizeof(cls); - - /* Address (in network byteorder, adjust masks). */ - uint64_t netblk = 0; - if (remote->ss_family == AF_INET6) { - struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)remote; - memcpy(&netblk, &ipv6->sin6_addr, RRL_V6_PREFIX_LEN); - } else { - struct sockaddr_in *ipv4 = (struct sockaddr_in *)remote; - memcpy(&netblk, &ipv4->sin_addr, RRL_V4_PREFIX_LEN); - } - memcpy(dst + blklen, &netblk, sizeof(netblk)); - blklen += sizeof(netblk); - - /* Name */ - int ret = rrl_clsname(dst + blklen, maxlen - blklen, cls, req, name); - if (ret < 0) { - return ret; - } - uint8_t len = ret; - blklen += len; - - return blklen; -} - -static int bucket_free(rrl_item_t *bucket, uint32_t now) -{ - return bucket->cls == CLS_NULL || (bucket->time + 1 < now); -} - -static int bucket_match(rrl_item_t *bucket, rrl_item_t *match) -{ - return bucket->cls == match->cls && - bucket->netblk == match->netblk && - bucket->qname == match->qname; -} - -static int find_free(rrl_table_t *tbl, unsigned id, uint32_t now) -{ - for (int i = id; i < tbl->size; i++) { - if (bucket_free(&tbl->arr[i], now)) { - return i - id; - } - } - for (int i = 0; i < id; i++) { - if (bucket_free(&tbl->arr[i], now)) { - return i + (tbl->size - id); - } - } - - /* this happens if table is full... force vacate current elm */ - return id; -} - -static inline unsigned find_match(rrl_table_t *tbl, uint32_t id, rrl_item_t *m) -{ - unsigned new_id = 0; - unsigned hop = 0; - unsigned match_bitmap = tbl->arr[id].hop; - while (match_bitmap != 0) { - hop = __builtin_ctz(match_bitmap); /* offset of next potential match */ - new_id = (id + hop) % tbl->size; - if (bucket_match(&tbl->arr[new_id], m)) { - return hop; - } else { - match_bitmap &= ~(1 << hop); /* clear potential match */ - } - } - - return HOP_LEN + 1; -} - -static inline unsigned reduce_dist(rrl_table_t *tbl, unsigned id, unsigned dist, unsigned *free_id) -{ - unsigned rd = HOP_LEN - 1; - while (rd > 0) { - unsigned vacate_id = (tbl->size + *free_id - rd) % tbl->size; /* bucket to be vacated */ - if (tbl->arr[vacate_id].hop != 0) { - unsigned hop = __builtin_ctz(tbl->arr[vacate_id].hop); /* offset of first valid bucket */ - if (hop < rd) { /* only offsets in <vacate_id, free_id> are interesting */ - unsigned new_id = (vacate_id + hop) % tbl->size; /* this item will be displaced to [free_id] */ - unsigned keep_hop = tbl->arr[*free_id].hop; /* unpredictable padding */ - memcpy(tbl->arr + *free_id, tbl->arr + new_id, sizeof(rrl_item_t)); - tbl->arr[*free_id].hop = keep_hop; - tbl->arr[new_id].cls = CLS_NULL; - tbl->arr[vacate_id].hop &= ~(1 << hop); - tbl->arr[vacate_id].hop |= 1 << rd; - *free_id = new_id; - return dist - (rd - hop); - } - } - --rd; - } - - assert(rd == 0); /* this happens with p=1/fact(HOP_LEN) */ - *free_id = id; - dist = 0; /* force vacate initial element */ - return dist; -} - -static void subnet_tostr(char *dst, size_t maxlen, const struct sockaddr_storage *ss) -{ const void *addr; - const char *suffix; if (ss->ss_family == AF_INET6) { addr = &((struct sockaddr_in6 *)ss)->sin6_addr; - suffix = "/56"; } else { addr = &((struct sockaddr_in *)ss)->sin_addr; - suffix = "/24"; } - if (knot_inet_ntop(ss->ss_family, addr, dst, maxlen) != NULL) { - strlcat(dst, suffix, maxlen); - } else { + if (knot_inet_ntop(ss->ss_family, addr, dst, maxlen) == NULL) { dst[0] = '\0'; } } -static void rrl_log_state(knotd_mod_t *mod, const struct sockaddr_storage *ss, - uint16_t flags, uint8_t cls, const knot_dname_t *qname) +static void rrl_log_limited(knotd_mod_t *mod, const struct sockaddr_storage *ss, + const uint8_t prefix, bool rate) { - if (mod == NULL || ss == NULL) { + if (mod == NULL) { return; } char addr_str[SOCKADDR_STRLEN]; - subnet_tostr(addr_str, sizeof(addr_str), ss); - - const char *what = "leaves"; - if (flags & RRL_BF_ELIMIT) { - what = "enters"; - } + addr_tostr(addr_str, sizeof(addr_str), ss); - knot_dname_txt_storage_t buf; - char *qname_str = knot_dname_to_str(buf, qname, sizeof(buf)); - if (qname_str == NULL) { - qname_str = "?"; - } - - knotd_mod_log(mod, LOG_NOTICE, "address/subnet %s, class %s, qname %s, %s limiting", - addr_str, rrl_clsstr(cls), qname_str, what); + knotd_mod_log(mod, LOG_NOTICE, "address %s limited on /%d by %s", + addr_str, prefix, rate ? "rate" : "time"); } -static void rrl_lock(rrl_table_t *tbl, int lk_id) +rrl_table_t *rrl_create(size_t size, uint32_t instant_limit, uint32_t rate_limit, + bool rw_mode, uint32_t log_period) { - assert(lk_id > -1); - pthread_mutex_lock(tbl->lk + lk_id); -} - -static void rrl_unlock(rrl_table_t *tbl, int lk_id) -{ - assert(lk_id > -1); - pthread_mutex_unlock(tbl->lk + lk_id); -} - -static int rrl_setlocks(rrl_table_t *tbl, uint32_t granularity) -{ - assert(!tbl->lk); /* Cannot change while locks are used. */ - assert(granularity <= tbl->size / 10); /* Due to int. division err. */ - - if (pthread_mutex_init(&tbl->ll, NULL) < 0) { - return KNOT_ENOMEM; + if (size == 0 || instant_limit == 0 || rate_limit == 0) { + return NULL; } - /* Alloc new locks. */ - tbl->lk = malloc(granularity * sizeof(pthread_mutex_t)); - if (!tbl->lk) { - return KNOT_ENOMEM; - } - memset(tbl->lk, 0, granularity * sizeof(pthread_mutex_t)); + size--; + size_t capacity_log = 1; + while (size >>= 1) capacity_log++; - /* Initialize. */ - for (size_t i = 0; i < granularity; ++i) { - if (pthread_mutex_init(tbl->lk + i, NULL) < 0) { - break; - } - ++tbl->lk_count; + rrl_table_t *rrl; + size_t rrl_size = offsetof(struct rrl_table, kru) + KRU.get_size(capacity_log); + if (posix_memalign((void **)&rrl, 64, rrl_size) != 0) { + return NULL; } + memset(rrl, 0, rrl_size); - /* Incomplete initialization */ - if (tbl->lk_count != granularity) { - for (size_t i = 0; i < tbl->lk_count; ++i) { - pthread_mutex_destroy(tbl->lk + i); - } - free(tbl->lk); - tbl->lk_count = 0; - return KNOT_ERROR; + assert(rate_limit <= 1000ll * instant_limit); // Ensured by config check. + kru_price_t base_price = KRU_LIMIT / instant_limit; + const kru_price_t max_decay = (uint64_t)base_price * rate_limit / 1000; + if (!rw_mode) { + base_price = base_price * RRL_LIMIT_KOEF; } - return KNOT_EOK; -} - -rrl_table_t *rrl_create(size_t size, uint32_t rate) -{ - if (size == 0) { + if (!KRU.initialize((struct kru *)rrl->kru, capacity_log, max_decay)) { + free(rrl); return NULL; } - const size_t tbl_len = sizeof(rrl_table_t) + size * sizeof(rrl_item_t); - rrl_table_t *tbl = calloc(1, tbl_len); - if (!tbl) { - return NULL; + for (size_t i = 0; i < RRL_V4_PREFIXES_CNT; i++) { + rrl->v4_prices[i] = base_price / RRL_V4_RATE_MULT[i]; } - tbl->size = size; - tbl->rate = rate; - if (dnssec_random_buffer((uint8_t *)&tbl->key, sizeof(tbl->key)) != DNSSEC_EOK) { - free(tbl); - return NULL; + for (size_t i = 0; i < RRL_V6_PREFIXES_CNT; i++) { + rrl->v6_prices[i] = base_price / RRL_V6_RATE_MULT[i]; } - if (rrl_setlocks(tbl, RRL_LOCK_GRANULARITY) != KNOT_EOK) { - free(tbl); - return NULL; - } + rrl->rw_mode = rw_mode; + rrl->log_period = log_period; - return tbl; -} + struct timespec now_ts; + clock_gettime(CLOCK_MONOTONIC_COARSE, &now_ts); + uint32_t now = now_ts.tv_sec * 1000 + now_ts.tv_nsec / 1000000; + rrl->log_time = now - log_period; -static knot_dname_t *buf_qname(uint8_t *buf) -{ - return buf + sizeof(uint8_t) + sizeof(uint64_t); + return rrl; } -/*! \brief Get bucket for current combination of parameters. */ -static rrl_item_t *rrl_hash(rrl_table_t *tbl, const struct sockaddr_storage *remote, - rrl_req_t *req, const knot_dname_t *zone, uint32_t stamp, - int *lock, uint8_t *buf, size_t buf_len) +int rrl_query(rrl_table_t *rrl, const struct sockaddr_storage *remote, knotd_mod_t *mod) { - int len = rrl_classify(buf, buf_len, remote, req, zone); - if (len < 0) { - return NULL; - } + assert(rrl); + assert(remote); - uint32_t id = SipHash24(&tbl->key, buf, len) % tbl->size; - - /* Lock for lookup. */ - pthread_mutex_lock(&tbl->ll); - - /* Find an exact match in <id, id + HOP_LEN). */ - knot_dname_t *qname = buf_qname(buf); - uint64_t netblk; - memcpy(&netblk, buf + sizeof(uint8_t), sizeof(netblk)); - rrl_item_t match = { - .hop = 0, - .netblk = netblk, - .ntok = tbl->rate * RRL_CAPACITY, - .cls = buf[0], - .flags = RRL_BF_NULL, - .qname = SipHash24(&tbl->key, qname, knot_dname_size(qname)), - .time = stamp - }; - - unsigned dist = find_match(tbl, id, &match); - if (dist > HOP_LEN) { /* not an exact match, find free element [f] */ - dist = find_free(tbl, id, stamp); - } + struct timespec now_ts; + clock_gettime(CLOCK_MONOTONIC_COARSE, &now_ts); + uint32_t now = now_ts.tv_sec * 1000 + now_ts.tv_nsec / 1000000; - /* Reduce distance to fit <id, id + HOP_LEN) */ - unsigned free_id = (id + dist) % tbl->size; - while (dist >= HOP_LEN) { - dist = reduce_dist(tbl, id, dist, &free_id); - } + uint16_t load = 0; + uint8_t prefix = 0; + _Alignas(16) uint8_t key[16] = { 0 }; + if (remote->ss_family == AF_INET6) { + struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)remote; + memcpy(key, &ipv6->sin6_addr, 16); - /* Assign granular lock and unlock lookup. */ - *lock = free_id % tbl->lk_count; - rrl_lock(tbl, *lock); - pthread_mutex_unlock(&tbl->ll); - - /* found free bucket which is in <id, id + HOP_LEN) */ - tbl->arr[id].hop |= (1 << dist); - rrl_item_t *bucket = &tbl->arr[free_id]; - assert(free_id == (id + dist) % tbl->size); - - /* Inspect bucket state. */ - unsigned hop = bucket->hop; - if (bucket->cls == CLS_NULL) { - memcpy(bucket, &match, sizeof(rrl_item_t)); - bucket->hop = hop; + if (rrl->rw_mode) { + prefix = KRU.limited_multi_prefix_or( + (struct kru *)rrl->kru, now, 1, key, RRL_V6_PREFIXES, + rrl->v6_prices, RRL_V6_PREFIXES_CNT, NULL); + } else { + load = KRU.load_multi_prefix_max( + (struct kru *)rrl->kru, now, 1, key, RRL_V6_PREFIXES, + NULL, RRL_V6_PREFIXES_CNT, &prefix); + } + } else { + struct sockaddr_in *ipv4 = (struct sockaddr_in *)remote; + memcpy(key, &ipv4->sin_addr, 4); + + if (rrl->rw_mode) { + prefix = KRU.limited_multi_prefix_or( + (struct kru *)rrl->kru, now, 0, key, RRL_V4_PREFIXES, + rrl->v4_prices, RRL_V4_PREFIXES_CNT, NULL); + } else { + load = KRU.load_multi_prefix_max( + (struct kru *)rrl->kru, now, 0, key, RRL_V4_PREFIXES, + NULL, RRL_V4_PREFIXES_CNT, &prefix); + } } - /* Check for collisions. */ - if (!bucket_match(bucket, &match)) { - if (!(bucket->flags & RRL_BF_SSTART)) { - memcpy(bucket, &match, sizeof(rrl_item_t)); - bucket->hop = hop; - bucket->ntok = tbl->rate + tbl->rate / RRL_SSTART; - bucket->flags |= RRL_BF_SSTART; + + if (rrl->rw_mode) { + if (prefix == 0) { + return KNOT_EOK; } + } else { + if (load <= (1 << 16) * RRL_LIMIT_KOEF) { + return KNOT_EOK; + } + } + + uint32_t log_time_orig = atomic_load_explicit(&rrl->log_time, memory_order_relaxed); + if (rrl->log_period && (now - log_time_orig + 1024 >= rrl->log_period + 1024)) { + do { + if (atomic_compare_exchange_weak_explicit(&rrl->log_time, &log_time_orig, now, + memory_order_relaxed, memory_order_relaxed)) { + rrl_log_limited(mod, remote, prefix, rrl->rw_mode); + break; + } + } while (now - log_time_orig + 1024 >= rrl->log_period + 1024); } - return bucket; + return KNOT_ELIMIT; } -int rrl_query(rrl_table_t *rrl, const struct sockaddr_storage *remote, - rrl_req_t *req, const knot_dname_t *zone, knotd_mod_t *mod) +void rrl_update(rrl_table_t *rrl, const struct sockaddr_storage *remote, size_t value) { - if (!rrl || !req || !remote) { - return KNOT_EINVAL; - } + assert(rrl); + assert(remote); + assert(!rrl->rw_mode); - uint8_t buf[RRL_CLSBLK_MAXLEN]; + struct timespec now_ts; + clock_gettime(CLOCK_MONOTONIC_COARSE, &now_ts); + uint32_t now = now_ts.tv_sec * 1000 + now_ts.tv_nsec / 1000000; - /* Calculate hash and fetch */ - int ret = KNOT_EOK; - int lock = -1; - uint32_t now = time_now().tv_sec; - rrl_item_t *bucket = rrl_hash(rrl, remote, req, zone, now, &lock, buf, sizeof(buf)); - if (!bucket) { - if (lock > -1) { - rrl_unlock(rrl, lock); - } - return KNOT_ERROR; - } - - /* Calculate rate for dT */ - uint32_t dt = now - bucket->time; - if (dt > RRL_CAPACITY) { - dt = RRL_CAPACITY; - } - /* Visit bucket. */ - bucket->time = now; - if (dt > 0) { /* Window moved. */ - - /* Check state change. */ - if ((bucket->ntok > 0 || dt > 1) && (bucket->flags & RRL_BF_ELIMIT)) { - bucket->flags &= ~RRL_BF_ELIMIT; - rrl_log_state(mod, remote, bucket->flags, bucket->cls, - knot_pkt_qname(req->query)); - } + _Alignas(16) uint8_t key[16] = { 0 }; + if (remote->ss_family == AF_INET6) { + struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)remote; + memcpy(key, &ipv6->sin6_addr, 16); - /* Add new tokens. */ - uint32_t dn = rrl->rate * dt; - if (bucket->flags & RRL_BF_SSTART) { /* Bucket in slow-start. */ - bucket->flags &= ~RRL_BF_SSTART; - } - bucket->ntok += dn; - if (bucket->ntok > RRL_CAPACITY * rrl->rate) { - bucket->ntok = RRL_CAPACITY * rrl->rate; + kru_price_t prices[RRL_V6_PREFIXES_CNT]; + for (size_t i = 0; i < RRL_V6_PREFIXES_CNT; i++) { + prices[i] = MIN(value * rrl->v6_prices[i], (kru_price_t)-1LL); } - } - /* Last item taken. */ - if (bucket->ntok == 1 && !(bucket->flags & RRL_BF_ELIMIT)) { - bucket->flags |= RRL_BF_ELIMIT; - rrl_log_state(mod, remote, bucket->flags, bucket->cls, - knot_pkt_qname(req->query)); - } + (void)KRU.load_multi_prefix_max((struct kru *)rrl->kru, now, + 1, key, RRL_V6_PREFIXES, prices, + RRL_V6_PREFIXES_CNT, NULL); + } else { + struct sockaddr_in *ipv4 = (struct sockaddr_in *)remote; + memcpy(key, &ipv4->sin_addr, 4); - /* Decay current bucket. */ - if (bucket->ntok > 0) { - --bucket->ntok; - } else if (bucket->ntok == 0) { - ret = KNOT_ELIMIT; - } + kru_price_t prices[RRL_V4_PREFIXES_CNT]; + for (size_t i = 0; i < RRL_V4_PREFIXES_CNT; i++) { + prices[i] = MIN(value * rrl->v4_prices[i], (kru_price_t)-1LL); + } - if (lock > -1) { - rrl_unlock(rrl, lock); + (void)KRU.load_multi_prefix_max((struct kru *)rrl->kru, now, + 0, key, RRL_V4_PREFIXES, prices, + RRL_V4_PREFIXES_CNT, NULL); } - return ret; } bool rrl_slip_roll(int n_slip) @@ -540,15 +247,5 @@ bool rrl_slip_roll(int n_slip) void rrl_destroy(rrl_table_t *rrl) { - if (rrl) { - if (rrl->lk_count > 0) { - pthread_mutex_destroy(&rrl->ll); - } - for (size_t i = 0; i < rrl->lk_count; ++i) { - pthread_mutex_destroy(rrl->lk + i); - } - free(rrl->lk); - } - free(rrl); } diff --git a/src/knot/modules/rrl/functions.h b/src/knot/modules/rrl/functions.h index 0f09234..0941c83 100644 --- a/src/knot/modules/rrl/functions.h +++ b/src/knot/modules/rrl/functions.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -17,95 +17,63 @@ #pragma once #include <stdint.h> -#include <pthread.h> #include <sys/socket.h> -#include "libknot/libknot.h" #include "knot/include/module.h" -#include "contrib/openbsd/siphash.h" -/*! - * \brief RRL hash bucket. - */ -typedef struct { - unsigned hop; /* Hop bitmap. */ - uint64_t netblk; /* Prefix associated. */ - uint16_t ntok; /* Tokens available. */ - uint8_t cls; /* Bucket class. */ - uint8_t flags; /* Flags. */ - uint32_t qname; /* imputed(QNAME) hash. */ - uint32_t time; /* Timestamp. */ -} rrl_item_t; +typedef struct rrl_table rrl_table_t; /*! - * \brief RRL hash bucket table. + * \brief Create a RRL table. * - * Table is fixed size, so collisions may occur and are dealt with - * in a way, that hashbucket rate is reset and enters slow-start for 1 dt. - * When a bucket is in a slow-start mode, it cannot reset again for the time - * period. + * \param size Fixed table size. + * \param instant_limit Instant limit. + * \param rate_limit Rate limit. + * \param rw_mode If disabled, RW operation is divided into R and W operations. + * \param log_period If nonzero, maximum logging period (in milliseconds). * - * To avoid lock contention, N locks are created and distributed amongst buckets. - * As of now lock K for bucket N is calculated as K = N % (num_buckets). - */ - -typedef struct { - SIPHASH_KEY key; /* Siphash key. */ - uint32_t rate; /* Configured RRL limit. */ - pthread_mutex_t ll; - pthread_mutex_t *lk; /* Table locks. */ - unsigned lk_count; /* Table lock count (granularity). */ - size_t size; /* Number of buckets. */ - rrl_item_t arr[]; /* Buckets. */ -} rrl_table_t; - -/*! \brief RRL request flags. */ -typedef enum { - RRL_REQ_NOFLAG = 0 << 0, /*!< No flags. */ - RRL_REQ_WILDCARD = 1 << 1 /*!< Query to wildcard name. */ -} rrl_req_flag_t; - -/*! - * \brief RRL request descriptor. - */ -typedef struct { - const uint8_t *wire; - uint16_t len; - rrl_req_flag_t flags; - knot_pkt_t *query; -} rrl_req_t; - -/*! - * \brief Create a RRL table. - * \param size Fixed hashtable size (reasonable large prime is recommended). - * \param rate Rate (in pkts/sec). * \return created table or NULL. */ -rrl_table_t *rrl_create(size_t size, uint32_t rate); +rrl_table_t *rrl_create(size_t size, uint32_t instant_limit, uint32_t rate_limit, + bool rw_mode, uint32_t log_period); /*! * \brief Query the RRL table for accept or deny, when the rate limit is reached. * + * \note This function is common to both RW and non-RW modes! + * * \param rrl RRL table. * \param remote Source address. - * \param req RRL request (containing resp., flags and question). - * \param zone Zone name related to the response (or NULL). * \param mod Query module (needed for logging). + * * \retval KNOT_EOK if passed. * \retval KNOT_ELIMIT when the limit is reached. */ -int rrl_query(rrl_table_t *rrl, const struct sockaddr_storage *remote, - rrl_req_t *req, const knot_dname_t *zone, knotd_mod_t *mod); +int rrl_query(rrl_table_t *rrl, const struct sockaddr_storage *remote, knotd_mod_t *mod); + +/*! + * \brief Update the RRL table. + * + * \note This function is only for the non-RW mode! + * + * \param rrl RRL table. + * \param remote Source address. + * \param value Value with which the table is updated. + */ +void rrl_update(rrl_table_t *rrl, const struct sockaddr_storage *remote, size_t value); /*! * \brief Roll a dice whether answer slips or not. + * * \param n_slip Number represents every Nth answer that is slipped. + * * \return true or false */ bool rrl_slip_roll(int n_slip); /*! * \brief Destroy RRL table. + * * \param rrl RRL table. */ void rrl_destroy(rrl_table_t *rrl); diff --git a/src/knot/modules/rrl/kru-avx2.c b/src/knot/modules/rrl/kru-avx2.c new file mode 100644 index 0000000..183ae44 --- /dev/null +++ b/src/knot/modules/rrl/kru-avx2.c @@ -0,0 +1,66 @@ +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + 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 3 of the License, 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 <https://www.gnu.org/licenses/>. + */ + +// Checked with clang 5 (2017) and gcc 6 (2016). +// For other cases we'll rather keep just the generic implementation. +#if defined(__x86_64__) && (__clang_major__ >= 5 || __GNUC__ >= 6) + +// This file has code for new-ish x86 (2015+ usually, Atom 2021+) - AES + AVX2 +#if __clang_major__ >= 12 + #pragma clang attribute push (__attribute__((target("arch=x86-64-v3,aes"))), \ + apply_to = function) +#elif __clang__ + #pragma clang attribute push (__attribute__((target("avx2,aes"))), \ + apply_to = function) +#else + #pragma GCC push_options + #if __GNUC__ >= 11 + #pragma GCC target("arch=x86-64-v3,aes") + // try harder for auto-vectorization, etc. + #pragma GCC optimize("O3") + #else + #pragma GCC target("avx2,aes") + #endif +#endif + +#define USE_AES 1 +#define USE_AVX2 1 +#define USE_SSE41 1 + +#include "./kru.inc.c" +const struct kru_api KRU_AVX2 = KRU_API_INITIALIZER; + +#ifdef __clang__ + #pragma clang attribute pop +#else + #pragma GCC pop_options +#endif + +__attribute__((constructor)) +static void detect_CPU_avx2(void) +{ + // Checking just AES+AVX2 will most likely be OK even if we used arch=x86-64-v3 + if (__builtin_cpu_supports("aes") && __builtin_cpu_supports("avx2")) { + KRU = KRU_AVX2; + } +} + +#else + +#include "./kru.h" +const struct kru_api KRU_AVX2 = {NULL}; + +#endif diff --git a/src/knot/modules/rrl/kru-generic.c b/src/knot/modules/rrl/kru-generic.c new file mode 100644 index 0000000..71ffdd4 --- /dev/null +++ b/src/knot/modules/rrl/kru-generic.c @@ -0,0 +1,20 @@ +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + 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 3 of the License, 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 <https://www.gnu.org/licenses/>. + */ + +#include "./kru.inc.c" + +const struct kru_api KRU_GENERIC = KRU_API_INITIALIZER; +struct kru_api KRU = KRU_API_INITIALIZER; // generic version is the default diff --git a/src/knot/modules/rrl/kru.h b/src/knot/modules/rrl/kru.h new file mode 100644 index 0000000..7eef6c0 --- /dev/null +++ b/src/knot/modules/rrl/kru.h @@ -0,0 +1,90 @@ +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + 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 3 of the License, 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 <https://www.gnu.org/licenses/>. + */ + +#pragma once + +#include <stdbool.h> +#include <stddef.h> +#include <stdint.h> + +#define ALIGNED_CPU_CACHE _Alignas(64) + +// An unsigned integral type used for prices, blocking occurs when sum of prices overflows. +// Greater than 16-bit type enables randomized fractional incrementing as the internal counters are still 16-bit. +// Exponential decay always uses randomized rounding on 32 bits. +typedef uint32_t kru_price_t; + +#define KRU_PRICE_BITS (8 * sizeof(kru_price_t)) + +// maximal allowed sum of prices without limiting +#define KRU_LIMIT (((kru_price_t)-1ll) - (1ll << (KRU_PRICE_BITS - 16)) + 1) + +struct kru; + +/// Usage: KRU.limited(...) +struct kru_api { + /// Initialize a new KRU structure that can track roughly 2^capacity_log limited keys. + /// + /// The kru parameter should point to a zeroed preallocated memory + /// of size returned by get_size aligned to 64-bytes; + /// deallocate the memory to destroy KRU. + /// RAM: the current parametrization will use roughly 8 bytes * 2^capacity_log. + /// + /// The number of non-limited keys is basically arbitrary, + /// but the total sum of prices per tick (for queries returning false) + /// should not get over roughly 2^(capacity_log + 15). + /// Note that the _multi variants increase these totals + /// by tracking multiple keys in a single query. + /// + /// Returns false if kru is NULL or other failure occurs. + bool (*initialize)(struct kru *kru, int capacity_log, kru_price_t max_decay); + + /// Calculate size of the KRU structure. + size_t (*get_size)(int capacity_log); + + /// Determine if a key should get limited (and update the KRU). + /// key needs to be aligned to a multiple of 16 bytes. + bool (*limited)(struct kru *kru, uint32_t time_now, uint8_t key[static const 16], kru_price_t price); + + /// Multiple queries. Returns OR of answers. Updates KRU only if no query is blocked (and possibly on race). + bool (*limited_multi_or)(struct kru *kru, uint32_t time_now, uint8_t **keys, kru_price_t *prices, size_t queries_cnt); + + /// Same as previous but without short-circuit evaluation; for time measurement purposes. + bool (*limited_multi_or_nobreak)(struct kru *kru, uint32_t time_now, uint8_t ** keys, kru_price_t *prices, size_t queries_cnt); + + /// Multiple queries based on different prefixes of a single key. + /// Returns a prefix (value in prefixes) on which the key is blocked, or zero if all queries passed. + /// Updates KRU only if no query is blocked, unless a race condition occurs -- + /// in such a case all longer prefixes might have been updated. + /// The key of i-th query consists of prefixes[i] bits of key, prefixes[i], and namespace. + /// If zero is returned, *max_load_out (unless NULL) is set to + /// the maximum of final values of the involved counters normalized to the limit 2^16. + uint8_t (*limited_multi_prefix_or)(struct kru *kru, uint32_t time_now, + uint8_t namespace, uint8_t key[static 16], uint8_t *prefixes, kru_price_t *prices, size_t queries_cnt, uint16_t *max_load_out); + + /// Multiple queries based on different prefixes of a single key. + /// Returns the maximum of final values of the involved counters normalized to the limit 2^16 + /// and stores the corresponding prefix (value in prefixes) to *prefix_out (unless NULL). + /// Set prices to NULL to skip updating; otherwise, KRU is always updated, using maximal allowed value on overflow. + /// The key of i-th query consists of prefixes[i] bits of key, prefixes[i], and namespace. + uint16_t (*load_multi_prefix_max)(struct kru *kru, uint32_t time_now, + uint8_t namespace, uint8_t key[static 16], uint8_t *prefixes, kru_price_t *prices, size_t queries_cnt, uint8_t *prefix_out); +}; + +// The functions are stored this way to make it easier to switch +// implementation based on detected CPU. +extern struct kru_api KRU; +extern const struct kru_api KRU_GENERIC, KRU_AVX2; diff --git a/src/knot/modules/rrl/kru.inc.c b/src/knot/modules/rrl/kru.inc.c new file mode 100644 index 0000000..49e359e --- /dev/null +++ b/src/knot/modules/rrl/kru.inc.c @@ -0,0 +1,615 @@ +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + 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 3 of the License, 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 <https://www.gnu.org/licenses/>. + */ + +/* +KRU estimates recently pricey inputs + +Authors of the simple agorithm (without aging, multi-choice, etc.): + Metwally, D. Agrawal, and A. E. Abbadi. + Efficient computation of frequent and top-k elements in data streams. + In International Conference on Database Theory, 2005. + +With TABLE_COUNT > 1 we're improving reliability by utilizing the property that +longest buckets (cache-lines) get very much shortened, already by providing two choices: + https://en.wikipedia.org/wiki/2-choice_hashing + +The point is to answer point-queries that estimate if the item has been heavily used recently. +To give more weight to recent usage, we use aging via exponential decay (simple to compute). +That has applications for garbage collection of cache and various limiting scenario +(excessive rate, traffic, CPU, maybe RAM). + +### Choosing parameters + +Size (`loads_bits` = log2 length): + - The KRU takes 64 bytes * length * TABLE_COUNT + some small constants. + As TABLE_COUNT == 2 and loads_bits = capacity_log >> 4, we get capacity * 8 Bytes. + - The length should probably be at least something like the square of the number of utilized CPUs. + But this most likely won't be a limiting factor. +*/ + +#include <stdlib.h> +#include <assert.h> +#include <stdatomic.h> +#include <stdbool.h> +#include <stddef.h> +#include <string.h> +#include <math.h> + +#include "./kru.h" +#include "contrib/macros.h" +#include "libdnssec/error.h" +#include "libdnssec/random.h" +typedef uint64_t hash_t; +#if USE_AES + /// 4-8 rounds should be an OK choice, most likely. + #define AES_ROUNDS 4 +#else + #include "contrib/openbsd/siphash.h" + + /// 1,3 should be OK choice, probably. + enum { + SIPHASH_RC = 1, + SIPHASH_RF = 3, + }; +#endif + +#if USE_AVX2 || USE_SSE41 || USE_AES + #include <immintrin.h> + #include <x86intrin.h> +#endif + +/// Block of loads sharing the same time, so that we're more space-efficient. +/// It's exactly a single cache line. +struct load_cl { + ALIGNED_CPU_CACHE + _Atomic uint32_t time; + #define LOADS_LEN 15 + uint16_t ids[LOADS_LEN]; + uint16_t loads[LOADS_LEN]; +}; +static_assert(64 == sizeof(struct load_cl), "bad size of struct load_cl"); + +/// Parametrization for speed of decay. +struct decay_config { + /// Bit shift per tick, fractional + double shift_bits; + + /// Ticks to get zero loads + uint32_t max_ticks; + + uint32_t mult_cache[32]; +}; + +struct kru { +#if USE_AES + /// Hashing secret. Random but shared by all users of the table. + /// Let's not make it too large, so that header fits into 64 Bytes. + _Alignas(32) char hash_key[48]; +#else + /// Hashing secret. Random but shared by all users of the table. + SIPHASH_KEY hash_key; +#endif + struct decay_config decay; + + /// Length of `loads_cls`, stored as binary logarithm. + uint32_t loads_bits; + + #define TABLE_COUNT 2 + /// These are read-write. Each struct has exactly one cache line. + struct load_cl load_cls[][TABLE_COUNT]; +}; + +inline static uint64_t rand_bits(unsigned int bits) +{ + static _Thread_local uint64_t state = 3723796604792068981ull; + const uint64_t prime1 = 11737314301796036329ull; + const uint64_t prime2 = 3107264277052274849ull; + state = prime1 * state + prime2; + //return state & ((1 << bits) - 1); + return state >> (64 - bits); +} + +static inline void decay_initialize(struct decay_config *decay, kru_price_t max_decay) +{ + decay->shift_bits = log2(KRU_LIMIT - 1) - log2(KRU_LIMIT - 1 - max_decay); + decay->max_ticks = 18 / decay->shift_bits; + + decay->mult_cache[0] = 0; // not used + for (size_t ticks = 1; ticks < sizeof(decay->mult_cache) / sizeof(*decay->mult_cache); ticks++) { + decay->mult_cache[ticks] = exp2(32 - decay->shift_bits * ticks) + 0.5; + } +} + +/// Catch up the time drift with configurably slower decay. +static inline void update_time(struct load_cl *l, const uint32_t time_now, + const struct decay_config *decay) +{ + uint32_t ticks; + uint32_t time_last = atomic_load_explicit(&l->time, memory_order_relaxed); + do { + ticks = time_now - time_last; + if (__builtin_expect(!ticks, true)) // we optimize for time not advancing + return; + // We accept some desynchronization of time_now (e.g. from different threads). + if (ticks > (uint32_t)-1024) + return; + } while (!atomic_compare_exchange_weak_explicit(&l->time, &time_last, time_now, memory_order_relaxed, memory_order_relaxed)); + + // If we passed here, we have acquired a time difference we are responsibe for. + + // Don't bother with complex computations if lots of ticks have passed. (little to no speed-up) + if (ticks > decay->max_ticks) { + memset(l->loads, 0, sizeof(l->loads)); + return; + } + + uint32_t mult; + if (__builtin_expect(ticks < sizeof(decay->mult_cache) / sizeof(*decay->mult_cache), 1)) { + mult = decay->mult_cache[ticks]; + } else { + mult = exp2(32 - decay->shift_bits * ticks) + 0.5; + } + + for (int i = 0; i < LOADS_LEN; ++i) { + // We perform decay for the acquired time difference; decays from different threads are commutative. + _Atomic uint16_t *load_at = (_Atomic uint16_t *)&l->loads[i]; + uint16_t l1, load_orig = atomic_load_explicit(load_at, memory_order_relaxed); + const uint16_t rnd = rand_bits(16); + do { + uint64_t m = (((uint64_t)load_orig << 16)) * mult; + m = (m >> 32) + ((m >> 31) & 1); + l1 = (m >> 16) + (rnd < (uint16_t)m); + } while (!atomic_compare_exchange_weak_explicit(load_at, &load_orig, l1, memory_order_relaxed, memory_order_relaxed)); + } +} + +/// Convert capacity_log to loads_bits +static inline int32_t capacity2loads(int capacity_log) +{ + static_assert(LOADS_LEN == 15 && TABLE_COUNT == 2, ""); + // So, the pair of cache lines hold up to 2*15 elements. + // Let's say that we can reliably store 16 = 1 << (1+3). + // (probably more but certainly not 1 << 5) + const int shift = 1 + 3; + int loads_bits = capacity_log - shift; + // Let's behave reasonably for weird capacity_log values. + return loads_bits > 0 ? loads_bits : 1; +} + +static size_t kru_get_size(int capacity_log) +{ + uint32_t loads_bits = capacity2loads(capacity_log); + if (8 * sizeof(hash_t) < TABLE_COUNT * loads_bits + + 8 * sizeof(((struct kru *)0)->load_cls[0]->ids[0])) { + assert(false); + return 0; + } + + return offsetof(struct kru, load_cls) + + sizeof(struct load_cl) * TABLE_COUNT * (1 << loads_bits); +} + +static bool kru_initialize(struct kru *kru, int capacity_log, kru_price_t max_decay) +{ + if (!kru) { + return false; + } + + uint32_t loads_bits = capacity2loads(capacity_log); + if (8 * sizeof(hash_t) < TABLE_COUNT * loads_bits + + 8 * sizeof(((struct kru *)0)->load_cls[0]->ids[0])) { + assert(false); + return false; + } + + kru->loads_bits = loads_bits; + + if (dnssec_random_buffer((uint8_t *)&kru->hash_key, sizeof(kru->hash_key)) != DNSSEC_EOK) { + return false; + } + + decay_initialize(&kru->decay, max_decay); + + return true; +} + +struct query_ctx { + struct load_cl *l[TABLE_COUNT]; + uint32_t time_now; + kru_price_t price; + uint16_t price16, limit16; + uint16_t id; + uint16_t final_load_value; // set by kru_limited_update if not blocked + uint16_t *load; +}; + +/// Phase 1/3 of a query -- hash, prefetch, ctx init. Based on one 16-byte key. +static inline void kru_limited_prefetch(struct kru *kru, uint32_t time_now, uint8_t key[static 16], kru_price_t price, struct query_ctx *ctx) +{ + // Obtain hash of *buf. + hash_t hash; +#if !USE_AES + hash = SipHash(&kru->hash_key, SIPHASH_RC, SIPHASH_RF, key, 16); +#else + { + __m128i h; /// hashing state + h = _mm_load_si128((__m128i *)key); + // Now do the the hashing itself. + __m128i *aes_key = (void*)kru->hash_key; + for (int i = 0; i < AES_ROUNDS; ++i) { + int key_id = i % (sizeof(kru->hash_key) / sizeof(__m128i)); + h = _mm_aesenc_si128(h, _mm_load_si128(&aes_key[key_id])); + } + memcpy(&hash, &h, sizeof(hash)); + } +#endif + + // Choose the cache-lines to operate on + const uint32_t loads_mask = (1 << kru->loads_bits) - 1; + // Fetch the two cache-lines in parallel before we really touch them. + for (int li = 0; li < TABLE_COUNT; ++li) { + struct load_cl * const l = &kru->load_cls[hash & loads_mask][li]; + __builtin_prefetch(l, 0); // hope for read-only access + hash >>= kru->loads_bits; + ctx->l[li] = l; + } + + ctx->time_now = time_now; + ctx->price = price; + ctx->id = hash; +} + +/// Phase 1/3 of a query -- hash, prefetch, ctx init. Based on a bit prefix of one 16-byte key. +static inline void kru_limited_prefetch_prefix(struct kru *kru, uint32_t time_now, uint8_t namespace, uint8_t key[static 16], uint8_t prefix, kru_price_t price, struct query_ctx *ctx) +{ + // Obtain hash of *buf. + hash_t hash; + +#if !USE_AES + { + const int rc = SIPHASH_RC, rf = SIPHASH_RF; + + // Hash prefix of key, prefix size, and namespace together. + SIPHASH_CTX hctx; + SipHash_Init(&hctx, &kru->hash_key); + SipHash_Update(&hctx, rc, rf, &namespace, sizeof(namespace)); + SipHash_Update(&hctx, rc, rf, &prefix, sizeof(prefix)); + SipHash_Update(&hctx, rc, rf, key, prefix / 8); + if (prefix % 8) { + const uint8_t masked_byte = key[prefix / 8] & (0xFF00 >> (prefix % 8)); + SipHash_Update(&hctx, rc, rf, &masked_byte, 1); + } + hash = SipHash_End(&hctx, rc, rf); + } +#else + { + + __m128i h; /// hashing state + h = _mm_load_si128((__m128i *)key); + + { // Keep only the prefix. + const uint8_t p = prefix; + + // Prefix mask (1...0) -> little endian byte array (0x00 ... 0x00 0xFF ... 0xFF). + __m128i mask = _mm_set_epi64x( + (p < 64 ? (p == 0 ? 0 : (uint64_t)-1 << (64 - p)) : (uint64_t)-1), // higher 64 bits (1...) -> second half of byte array (... 0xFF) + (p <= 64 ? 0 : (uint64_t)-1 << (128 - p))); // lower 64 bits (...0) -> first half of byte array (0x00 ...) + + // Swap mask endianness (0x11 ... 0x11 0x00 ... 0x00). + mask = _mm_shuffle_epi8(mask, + _mm_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15)); + + // Apply mask. + h = _mm_and_si128(h, mask); + } + + // Now do the the hashing itself. + __m128i *aes_key = (void*)kru->hash_key; + { + // Mix namespace and prefix size into the first aes key. + __m128i aes_key1 = _mm_insert_epi16(_mm_load_si128(aes_key), (namespace << 8) | prefix, 0); + h = _mm_aesenc_si128(h, aes_key1); + } + for (int j = 1; j < AES_ROUNDS; ++j) { + int key_id = j % (sizeof(kru->hash_key) / sizeof(__m128i)); + h = _mm_aesenc_si128(h, _mm_load_si128(&aes_key[key_id])); + } + memcpy(&hash, &h, sizeof(hash)); + } +#endif + + // Choose the cache-lines to operate on + const uint32_t loads_mask = (1 << kru->loads_bits) - 1; + // Fetch the two cache-lines in parallel before we really touch them. + for (int li = 0; li < TABLE_COUNT; ++li) { + struct load_cl * const l = &kru->load_cls[hash & loads_mask][li]; + __builtin_prefetch(l, 0); // hope for read-only access + hash >>= kru->loads_bits; + ctx->l[li] = l; + } + + ctx->time_now = time_now; + ctx->price = price; + ctx->id = hash; +} + +/// Phase 2/3 of a query -- returns answer with no state modification (except update_time). +static inline bool kru_limited_fetch(struct kru *kru, struct query_ctx *ctx) +{ + // Compute 16-bit limit and price. + // For 32-bit prices we assume that a 16-bit load value corresponds + // to the 32-bit value extended by low-significant ones and the limit is 2^32 (without ones). + // The 16-bit price is thus rounded up for the comparison with limit, + // but rounded probabilistically for rising the load. + { + const int fract_bits = 8 * sizeof(ctx->price) - 16; + const kru_price_t price = ctx->price; + const kru_price_t fract = price & ((((kru_price_t)1) << fract_bits) - 1); + + ctx->price16 = price >> fract_bits; + ctx->limit16 = -ctx->price16; + + if ((fract_bits > 0) && (fract > 0)) { + ctx->price16 += (rand_bits(fract_bits) < fract); + ctx->limit16--; + } + } + + for (int li = 0; li < TABLE_COUNT; ++li) { + update_time(ctx->l[li], ctx->time_now, &kru->decay); + } + + const uint16_t id = ctx->id; + + // Find matching element. Matching 16 bits in addition to loads_bits. + ctx->load = NULL; +#if !USE_AVX2 + for (int li = 0; li < TABLE_COUNT; ++li) + for (int i = 0; i < LOADS_LEN; ++i) + if (ctx->l[li]->ids[i] == id) { + ctx->load = &ctx->l[li]->loads[i]; + goto load_found; + } +#else + const __m256i id_v = _mm256_set1_epi16(id); + for (int li = 0; li < TABLE_COUNT; ++li) { + static_assert(LOADS_LEN == 15 && sizeof(ctx->l[li]->ids[0]) == 2, ""); + // unfortunately we can't use aligned load here + __m256i ids_v = _mm256_loadu_si256((__m256i *)((uint16_t *)ctx->l[li]->ids - 1)); + __m256i match_mask = _mm256_cmpeq_epi16(ids_v, id_v); + if (_mm256_testz_si256(match_mask, match_mask)) + continue; // no match of id + int index = _bit_scan_reverse(_mm256_movemask_epi8(match_mask)) / 2 - 1; + // there's a small possibility that we hit equality only on the -1 index + if (index >= 0) { + ctx->load = &ctx->l[li]->loads[index]; + goto load_found; + } + } +#endif + + ctx->final_load_value = 0; + return false; + +load_found:; + ctx->final_load_value = *ctx->load; + return (ctx->final_load_value >= ctx->limit16); +} + +/// Phase 3/3 of a query -- state update, return value overrides previous answer in case of race. +/// Not needed if blocked by fetch phase. If overflow_update is activated, false is always returned. +static inline bool kru_limited_update(struct kru *kru, struct query_ctx *ctx, bool overflow_update) +{ + _Atomic uint16_t *load_at; + if (!ctx->load) { + // No match, so find position of the smallest load. + int min_li = 0; + int min_i = 0; +#if !USE_SSE41 + for (int li = 0; li < TABLE_COUNT; ++li) + for (int i = 0; i < LOADS_LEN; ++i) + if (ctx->l[li]->loads[i] < ctx->l[min_li]->loads[min_i]) { + min_li = li; + min_i = i; + } +#else + int min_val = 0; + for (int li = 0; li < TABLE_COUNT; ++li) { + // BEWARE: we're relying on the exact memory layout of struct load_cl, + // where the .loads array take 15 16-bit values at the very end. + static_assert((offsetof(struct load_cl, loads) - 2) % 16 == 0, + "bad alignment of struct load_cl::loads"); + static_assert(LOADS_LEN == 15 && sizeof(ctx->l[li]->loads[0]) == 2, ""); + __m128i *l_v = (__m128i *)((uint16_t *)ctx->l[li]->loads - 1); + __m128i l0 = _mm_load_si128(l_v); + __m128i l1 = _mm_load_si128(l_v + 1); + // We want to avoid the first item in l0, so we maximize it. + // (but this function takes a signed integer, so -1 is the maximum) + l0 = _mm_insert_epi16(l0, -1, 0); + + // Only one instruction can find minimum and its position, + // and it works on 8x uint16_t. + __m128i mp0 = _mm_minpos_epu16(l0); + __m128i mp1 = _mm_minpos_epu16(l1); + int min0 = _mm_extract_epi16(mp0, 0); + int min1 = _mm_extract_epi16(mp1, 0); + int min01, min_ix; + if (min0 < min1) { + min01 = min0; + min_ix = _mm_extract_epi16(mp0, 1); + } else { + min01 = min1; + min_ix = 8 + _mm_extract_epi16(mp1, 1); + } + + if (li == 0 || min_val > min01) { + min_li = li; + min_i = min_ix; + min_val = min01; + } + } + // now, min_i (and min_ix) is offset by one due to alignment of .loads + if (min_i != 0) // zero is very unlikely + --min_i; +#endif + + ctx->l[min_li]->ids[min_i] = ctx->id; + load_at = (_Atomic uint16_t *)&ctx->l[min_li]->loads[min_i]; + } else { + load_at = (_Atomic uint16_t *)ctx->load; + } + + static_assert(ATOMIC_CHAR16_T_LOCK_FREE == 2, "insufficient atomics"); + const uint16_t price = ctx->price16; + const uint16_t limit = ctx->limit16; + uint16_t load_orig = atomic_load_explicit(load_at, memory_order_relaxed); + uint16_t load_new; + do { + if (load_orig >= limit) { + if (overflow_update) { + load_new = -1; + } else { + return true; + } + } else { + load_new = load_orig + price; + } + } while (!atomic_compare_exchange_weak_explicit(load_at, &load_orig, load_new, memory_order_relaxed, memory_order_relaxed)); + + ctx->final_load_value = load_new; + return false; +} + +static bool kru_limited_multi_or(struct kru *kru, uint32_t time_now, uint8_t **keys, kru_price_t *prices, size_t queries_cnt) +{ + struct query_ctx ctx[queries_cnt]; + + for (size_t i = 0; i < queries_cnt; i++) { + kru_limited_prefetch(kru, time_now, keys[i], prices[i], ctx + i); + } + for (size_t i = 0; i < queries_cnt; i++) { + if (kru_limited_fetch(kru, ctx + i)) + return true; + } + bool ret = false; + + for (size_t i = 0; i < queries_cnt; i++) { + ret |= kru_limited_update(kru, ctx + i, false); + } + + return ret; +} + +static bool kru_limited_multi_or_nobreak(struct kru *kru, uint32_t time_now, uint8_t **keys, kru_price_t *prices, size_t queries_cnt) +{ + struct query_ctx ctx[queries_cnt]; + bool ret = false; + + for (size_t i = 0; i < queries_cnt; i++) { + kru_limited_prefetch(kru, time_now, keys[i], prices[i], ctx + i); + } + for (size_t i = 0; i < queries_cnt; i++) { + if (kru_limited_fetch(kru, ctx + i)) + ret = true; + } + if (ret) return true; + + for (size_t i = 0; i < queries_cnt; i++) { + if (kru_limited_update(kru, ctx + i, false)) + ret = true; + } + + return ret; +} + +static uint8_t kru_limited_multi_prefix_or(struct kru *kru, uint32_t time_now, uint8_t namespace, + uint8_t key[static 16], uint8_t *prefixes, kru_price_t *prices, size_t queries_cnt, uint16_t *max_load_out) +{ + struct query_ctx ctx[queries_cnt]; + + for (size_t i = 0; i < queries_cnt; i++) { + kru_limited_prefetch_prefix(kru, time_now, namespace, key, prefixes[i], prices[i], ctx + i); + } + + for (size_t i = 0; i < queries_cnt; i++) { + if (kru_limited_fetch(kru, ctx + i)) + return prefixes[i]; + } + + for (int i = queries_cnt - 1; i >= 0; i--) { + if (kru_limited_update(kru, ctx + i, false)) + return prefixes[i]; + } + + if (max_load_out) { + *max_load_out = 0; + for (size_t i = 0; i < queries_cnt; i++) { + *max_load_out = MAX(*max_load_out, ctx[i].final_load_value); + } + } + + return 0; +} + +static uint16_t kru_load_multi_prefix_max(struct kru *kru, uint32_t time_now, uint8_t namespace, + uint8_t key[static 16], uint8_t *prefixes, kru_price_t *prices, size_t queries_cnt, uint8_t *prefix_out) +{ + struct query_ctx ctx[queries_cnt]; + + for (size_t i = 0; i < queries_cnt; i++) { + kru_limited_prefetch_prefix(kru, time_now, namespace, key, prefixes[i], (prices ? prices[i] : 0), ctx + i); + } + + for (size_t i = 0; i < queries_cnt; i++) { + kru_limited_fetch(kru, ctx + i); + } + + if (prices) { + for (int i = queries_cnt - 1; i >= 0; i--) { + kru_limited_update(kru, ctx + i, true); + } + } + + uint8_t prefix = 0; + uint16_t max_load = 0; + for (size_t i = 0; i < queries_cnt; i++) { + if (max_load < ctx[i].final_load_value) { + max_load = ctx[i].final_load_value; + prefix = prefixes[i]; + } + } + if (prefix_out) { + *prefix_out = prefix; + } + + return max_load; +} + +/// Update limiting and return true iff it hit the limit instead. +static bool kru_limited(struct kru *kru, uint32_t time_now, uint8_t key[static 16], kru_price_t price) +{ + return kru_limited_multi_or(kru, time_now, &key, &price, 1); +} + +#define KRU_API_INITIALIZER { \ + .get_size = kru_get_size, \ + .initialize = kru_initialize, \ + .limited = kru_limited, \ + .limited_multi_or = kru_limited_multi_or, \ + .limited_multi_or_nobreak = kru_limited_multi_or_nobreak, \ + .limited_multi_prefix_or = kru_limited_multi_prefix_or, \ + .load_multi_prefix_max = kru_load_multi_prefix_max, \ +} diff --git a/src/knot/modules/rrl/rrl.c b/src/knot/modules/rrl/rrl.c index 64f6cbf..d1ec7b5 100644 --- a/src/knot/modules/rrl/rrl.c +++ b/src/knot/modules/rrl/rrl.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -14,28 +14,47 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. */ +#include "contrib/time.h" #include "knot/include/module.h" -#include "knot/nameserver/process_query.h" // Dependency on qdata->extra! #include "knot/modules/rrl/functions.h" +#include "knot/modules/rrl/kru.h" #define MOD_RATE_LIMIT "\x0A""rate-limit" +#define MOD_INST_LIMIT "\x0D""instant-limit" +#define MOD_T_RATE_LIMIT "\x0F""time-rate-limit" +#define MOD_T_INST_LIMIT "\x12""time-instant-limit" #define MOD_SLIP "\x04""slip" #define MOD_TBL_SIZE "\x0A""table-size" #define MOD_WHITELIST "\x09""whitelist" +#define MOD_LOG_PERIOD "\x0A""log-period" +#define MOD_DRY_RUN "\x07""dry-run" const yp_item_t rrl_conf[] = { - { MOD_RATE_LIMIT, YP_TINT, YP_VINT = { 1, INT32_MAX } }, - { MOD_SLIP, YP_TINT, YP_VINT = { 0, 100, 1 } }, - { MOD_TBL_SIZE, YP_TINT, YP_VINT = { 1, INT32_MAX, 393241 } }, - { MOD_WHITELIST, YP_TNET, YP_VNONE, YP_FMULTI }, + { MOD_INST_LIMIT, YP_TINT, YP_VINT = { 1, (1ll << 32) / 768 - 1, 50 } }, + { MOD_RATE_LIMIT, YP_TINT, YP_VINT = { 0, ((1ll << 32) / 768 - 1) * 1000, 20 } }, + { MOD_T_INST_LIMIT, YP_TINT, YP_VINT = { 1, 1000000, 5000 } }, + { MOD_T_RATE_LIMIT, YP_TINT, YP_VINT = { 0, 1000000000, 4000 } }, + { MOD_SLIP, YP_TINT, YP_VINT = { 0, 100, 1 } }, + { MOD_TBL_SIZE, YP_TINT, YP_VINT = { 1, INT32_MAX, 524288 } }, + { MOD_WHITELIST, YP_TNET, YP_VNONE, YP_FMULTI }, + { MOD_LOG_PERIOD, YP_TINT, YP_VINT = { 0, INT32_MAX, 0 } }, + { MOD_DRY_RUN, YP_TBOOL, YP_VNONE }, { NULL } }; int rrl_conf_check(knotd_conf_check_args_t *args) { - knotd_conf_t limit = knotd_conf_check_item(args, MOD_RATE_LIMIT); - if (limit.count == 0) { - args->err_str = "no rate limit specified"; + knotd_conf_t rate_limit = knotd_conf_check_item(args, MOD_RATE_LIMIT); + knotd_conf_t inst_limit = knotd_conf_check_item(args, MOD_INST_LIMIT); + if (rate_limit.single.integer > 1000ll * inst_limit.single.integer) { + args->err_str = "rate limit is higher than 1000 times instant rate limit"; + return KNOT_EINVAL; + } + + knotd_conf_t t_rate_limit = knotd_conf_check_item(args, MOD_T_RATE_LIMIT); + knotd_conf_t t_inst_limit = knotd_conf_check_item(args, MOD_T_INST_LIMIT); + if (t_rate_limit.single.integer > 1000ll * t_inst_limit.single.integer) { + args->err_str = "time rate limit is higher than 1000 times time instant limit"; return KNOT_EINVAL; } @@ -43,35 +62,78 @@ int rrl_conf_check(knotd_conf_check_args_t *args) } typedef struct { - rrl_table_t *rrl; + ALIGNED_CPU_CACHE // Ensures that one thread context occupies one cache line. + struct timespec start_time; // Start time of the measurement. + bool whitelist_checked; // Indication whether whitelist check took place. + bool skip; // Skip the rest of the module callbacks. +} thrd_ctx_t; + +typedef struct { + rrl_table_t *rate_table; + rrl_table_t *time_table; + thrd_ctx_t *thrd_ctx; int slip; + bool dry_run; knotd_conf_t whitelist; } rrl_ctx_t; -static const knot_dname_t *name_from_rrsig(const knot_rrset_t *rr) +static uint32_t time_diff_us(const struct timespec *begin, const struct timespec *end) +{ + struct timespec result = time_diff(begin, end); + return (result.tv_sec * 1000000) + (result.tv_nsec / 1000); +} + +static knotd_proto_state_t protolimit_start(knotd_proto_state_t state, + knotd_qdata_params_t *params, + knotd_mod_t *mod) { - if (rr == NULL) { - return NULL; + rrl_ctx_t *ctx = knotd_mod_ctx(mod); + thrd_ctx_t *thrd = &ctx->thrd_ctx[params->thread_id]; + thrd->skip = false; + + // Check if a whitelisted client. + thrd->whitelist_checked = true; + if (knotd_conf_addr_range_match(&ctx->whitelist, params->remote)) { + thrd->skip = true; + return state; } - if (rr->type != KNOT_RRTYPE_RRSIG) { - return NULL; + + // UDP time limiting not implemented (source address can be forged). + if (params->proto == KNOTD_QUERY_PROTO_UDP) { + return state; } - // This is a signature. - return knot_rrsig_signer_name(rr->rrs.rdata); + // Check if the packet is limited. + if (rrl_query(ctx->time_table, params->remote, mod) != KNOT_EOK) { + thrd->skip = true; + knotd_mod_stats_incr(mod, params->thread_id, 2, 0, 1); + return ctx->dry_run ? state : KNOTD_PROTO_STATE_BLOCK; + } else { + clock_gettime(CLOCK_THREAD_CPUTIME_ID, &thrd->start_time); + return state; // Not limited. + } } -static const knot_dname_t *name_from_authrr(const knot_rrset_t *rr) +static knotd_proto_state_t protolimit_end(knotd_proto_state_t state, + knotd_qdata_params_t *params, + knotd_mod_t *mod) { - if (rr == NULL) { - return NULL; + rrl_ctx_t *ctx = knotd_mod_ctx(mod); + thrd_ctx_t *thrd = &ctx->thrd_ctx[params->thread_id]; + + if (thrd->skip || params->proto == KNOTD_QUERY_PROTO_UDP) { + return state; } - if (rr->type != KNOT_RRTYPE_NS && rr->type != KNOT_RRTYPE_SOA) { - return NULL; + + // Update the time table. + struct timespec end_time; + clock_gettime(CLOCK_THREAD_CPUTIME_ID, &end_time); + uint64_t diff = time_diff_us(&thrd->start_time, &end_time); + if (diff > 0) { // Zero KRU update is NOOP. + rrl_update(ctx->time_table, params->remote, diff); } - // This is a valid authority RR. - return rr->owner; + return state; } static knotd_state_t ratelimit_apply(knotd_state_t state, knot_pkt_t *pkt, @@ -80,57 +142,36 @@ static knotd_state_t ratelimit_apply(knotd_state_t state, knot_pkt_t *pkt, assert(pkt && qdata && mod); rrl_ctx_t *ctx = knotd_mod_ctx(mod); + thrd_ctx_t *thrd = &ctx->thrd_ctx[qdata->params->thread_id]; - // Rate limit is applied to pure UDP only. - if (qdata->params->proto != KNOTD_QUERY_PROTO_UDP) { + if (thrd->skip) { return state; } - // Rate limit is not applied to responses with a valid cookie. - if (qdata->params->flags & KNOTD_QUERY_FLAG_COOKIE) { + // Don't limit authorized operations. + if (qdata->params->flags & KNOTD_QUERY_FLAG_AUTHORIZED) { + thrd->skip = true; return state; } - // Exempt clients. - if (knotd_conf_addr_range_match(&ctx->whitelist, knotd_qdata_remote_addr(qdata))) { + // Rate limit is applied to UDP only. + if (qdata->params->proto != KNOTD_QUERY_PROTO_UDP) { return state; } - rrl_req_t req = { - .wire = pkt->wire, - .query = qdata->query - }; - - if (!EMPTY_LIST(qdata->extra->wildcards)) { - req.flags = RRL_REQ_WILDCARD; - } - - // Take the zone name if known. - const knot_dname_t *zone_name = knotd_qdata_zone_name(qdata); - - // Take the signer name as zone name if there is an RRSIG. - if (zone_name == NULL) { - const knot_pktsection_t *ans = knot_pkt_section(pkt, KNOT_ANSWER); - for (int i = 0; i < ans->count; i++) { - zone_name = name_from_rrsig(knot_pkt_rr(ans, i)); - if (zone_name != NULL) { - break; - } - } + // Check for whitelisted client IF PER-ZONE module (no proto callbacks). + if (!thrd->whitelist_checked && + knotd_conf_addr_range_match(&ctx->whitelist, qdata->params->remote)) { + thrd->skip = true; + return state; } - // Take the NS or SOA owner name if there is no RRSIG. - if (zone_name == NULL) { - const knot_pktsection_t *auth = knot_pkt_section(pkt, KNOT_AUTHORITY); - for (int i = 0; i < auth->count; i++) { - zone_name = name_from_authrr(knot_pkt_rr(auth, i)); - if (zone_name != NULL) { - break; - } - } + // Rate limit is not applied to responses with a valid cookie. + if (qdata->params->flags & KNOTD_QUERY_FLAG_COOKIE) { + return state; } - if (rrl_query(ctx->rrl, knotd_qdata_remote_addr(qdata), &req, zone_name, mod) == KNOT_EOK) { + if (rrl_query(ctx->rate_table, knotd_qdata_remote_addr(qdata), mod) == KNOT_EOK) { // Rate limiting not applied. return state; } @@ -139,11 +180,11 @@ static knotd_state_t ratelimit_apply(knotd_state_t state, knot_pkt_t *pkt, // Slip the answer. knotd_mod_stats_incr(mod, qdata->params->thread_id, 0, 0, 1); qdata->err_truncated = true; - return KNOTD_STATE_FAIL; + return ctx->dry_run ? state : KNOTD_STATE_FAIL; } else { // Drop the answer. knotd_mod_stats_incr(mod, qdata->params->thread_id, 1, 0, 1); - return KNOTD_STATE_NOOP; + return ctx->dry_run ? state : KNOTD_STATE_NOOP; } } @@ -151,58 +192,96 @@ static void ctx_free(rrl_ctx_t *ctx) { assert(ctx); - rrl_destroy(ctx->rrl); + free(ctx->thrd_ctx); + rrl_destroy(ctx->rate_table); + rrl_destroy(ctx->time_table); + knotd_conf_free(&ctx->whitelist); free(ctx); } int rrl_load(knotd_mod_t *mod) { - // Create RRL context. rrl_ctx_t *ctx = calloc(1, sizeof(rrl_ctx_t)); if (ctx == NULL) { return KNOT_ENOMEM; } - // Create table. - uint32_t rate = knotd_conf_mod(mod, MOD_RATE_LIMIT).single.integer; - size_t size = knotd_conf_mod(mod, MOD_TBL_SIZE).single.integer; - ctx->rrl = rrl_create(size, rate); - if (ctx->rrl == NULL) { + ctx->dry_run = knotd_conf_mod(mod, MOD_DRY_RUN).single.boolean; + ctx->whitelist = knotd_conf_mod(mod, MOD_WHITELIST); + + ctx->thrd_ctx = calloc(knotd_mod_threads(mod), sizeof(*ctx->thrd_ctx)); + if (ctx->thrd_ctx == NULL) { ctx_free(ctx); return KNOT_ENOMEM; } - // Get slip. - ctx->slip = knotd_conf_mod(mod, MOD_SLIP).single.integer; + size_t size = knotd_conf_mod(mod, MOD_TBL_SIZE).single.integer; + uint32_t log_period = knotd_conf_mod(mod, MOD_LOG_PERIOD).single.integer; + + uint32_t rate_limit = knotd_conf_mod(mod, MOD_RATE_LIMIT).single.integer; + if (rate_limit > 0) { + uint32_t inst_limit = knotd_conf_mod(mod, MOD_INST_LIMIT).single.integer; + ctx->rate_table = rrl_create(size, inst_limit, rate_limit, true, log_period); + if (ctx->rate_table == NULL) { + ctx_free(ctx); + return KNOT_ENOMEM; + } + ctx->slip = knotd_conf_mod(mod, MOD_SLIP).single.integer; + } - // Get whitelist. - ctx->whitelist = knotd_conf_mod(mod, MOD_WHITELIST); + uint32_t time_limit = knotd_conf_mod(mod, MOD_T_RATE_LIMIT).single.integer; + if (time_limit > 0) { + uint32_t inst_limit = knotd_conf_mod(mod, MOD_T_INST_LIMIT).single.integer; + ctx->time_table = rrl_create(size, inst_limit, time_limit, false, log_period); + if (ctx->time_table == NULL) { + ctx_free(ctx); + return KNOT_ENOMEM; + } + } - // Set up statistics counters. int ret = knotd_mod_stats_add(mod, "slipped", 1, NULL); if (ret != KNOT_EOK) { ctx_free(ctx); return ret; } - ret = knotd_mod_stats_add(mod, "dropped", 1, NULL); if (ret != KNOT_EOK) { ctx_free(ctx); return ret; } + ret = knotd_mod_stats_add(mod, "dropped-time", 1, NULL); + if (ret != KNOT_EOK) { + ctx_free(ctx); + return ret; + } + + /* The explicit reference of the AVX2 variant ensures the optimized + * code isn't removed by linker if linking statically. + * Check: nm ./src/.libs/knotd | grep KRU_ + * https://stackoverflow.com/a/28663156/587396 + */ + knotd_mod_log(mod, LOG_DEBUG, "using %s implementation", + KRU.limited == KRU_AVX2.limited ? "optimized" : "generic"); knotd_mod_ctx_set(mod, ctx); - return knotd_mod_hook(mod, KNOTD_STAGE_END, ratelimit_apply); + if (rate_limit > 0) { + knotd_mod_hook(mod, KNOTD_STAGE_BEGIN, ratelimit_apply); + } + + if (time_limit > 0) { + // Note that these two callbacks aren't executed IF PER-ZONE module! + knotd_mod_proto_hook(mod, KNOTD_STAGE_PROTO_BEGIN, protolimit_start); + knotd_mod_proto_hook(mod, KNOTD_STAGE_PROTO_END, protolimit_end); + } + + return KNOT_EOK; } void rrl_unload(knotd_mod_t *mod) { - rrl_ctx_t *ctx = knotd_mod_ctx(mod); - - knotd_conf_free(&ctx->whitelist); - ctx_free(ctx); + ctx_free(knotd_mod_ctx(mod)); } -KNOTD_MOD_API(rrl, KNOTD_MOD_FLAG_SCOPE_ANY, +KNOTD_MOD_API(rrl, KNOTD_MOD_FLAG_SCOPE_ANY | KNOTD_MOD_FLAG_OPT_CONF, rrl_load, rrl_unload, rrl_conf, rrl_conf_check); diff --git a/src/knot/modules/rrl/rrl.rst b/src/knot/modules/rrl/rrl.rst index 0daae16..85c8d35 100644 --- a/src/knot/modules/rrl/rrl.rst +++ b/src/knot/modules/rrl/rrl.rst @@ -4,37 +4,52 @@ ================================ Response rate limiting (RRL) is a method to combat DNS reflection amplification -attacks. These attacks rely on the fact that source address of a UDP query +attacks. These attacks rely on the fact that the source address of a UDP query can be forged, and without a worldwide deployment of `BCP38 <https://tools.ietf.org/html/bcp38>`_, such a forgery cannot be prevented. An attacker can use a DNS server (or multiple servers) as an amplification -source and can flood a victim with a large number of unsolicited DNS responses. -The RRL lowers the amplification factor of these attacks by sending some of -the responses as truncated or by dropping them altogether. +source to flood a victim with a large number of unsolicited DNS responses. +RRL lowers the amplification factor of these attacks by sending some +responses as truncated or by dropping them altogether. + +This module can also help protect the server from excessive utilization by +limiting incoming packets (including handshakes) based on consumed time. +If a packet is time rate limited, it's dropped. This function works with +all supported non-UDP transport protocols and cannot be configured per zone. .. NOTE:: - The module introduces two statistics counters. The number of slipped and - dropped responses. + This module introduces three statistics counters: + + - ``slipped`` – The number of slipped UDP responses. + - ``dropped`` – The number of dropped UDP responses due to the rate limit. + - ``dropped-time`` – The number of dropped non-UDP packets due to the time rate limit. .. NOTE:: If the :ref:`Cookies<mod-cookies>` module is active, RRL is not applied - for responses with a valid DNS cookie. + to UDP responses with a valid DNS cookie. Example ------- -You can enable RRL by setting the module globally or per zone. +You can enable RRL by setting the module globally :: - mod-rrl: - - id: default - rate-limit: 200 # Allow 200 resp/s for each flow - slip: 2 # Approximately every other response slips - template: - id: default - global-module: mod-rrl/default # Enable RRL globally + global-module: mod-rrl # Default module configuration + +or per zone + +:: + + mod-rrl: + - id: custom + rate-limit: 200 + + zone: + - domain: example.com + module: mod-rrl/custom # Custom module configuration Module reference ---------------- @@ -44,9 +59,14 @@ Module reference mod-rrl: - id: STR rate-limit: INT + instant-limit: INT slip: INT + time-rate-limit: INT + time-instant-limit: INT table-size: INT whitelist: ADDR[/INT] | ADDR-ADDR | STR ... + log-period: INT + dry-run: BOOL .. _mod-rrl_id: @@ -60,30 +80,42 @@ A module identifier. rate-limit .......... -Rate limiting is based on the token bucket scheme. A rate basically -represents a number of tokens available each second. Each response is -processed and classified (based on several discriminators, e.g. -source netblock, query type, zone name, rcode, etc.). Classified responses are -then hashed and assigned to a bucket containing number of available -tokens, timestamp and metadata. When available tokens are exhausted, -response is dropped or sent as truncated (see :ref:`mod-rrl_slip`). -Number of available tokens is recalculated each second. +Maximal allowed number of UDP queries per second from a single IPv6 or IPv4 address. -*Required* +Rate limiting is performed for the whole address and several chosen prefixes. +The limits of prefixes are constant multiples of :ref:`mod-rrl_rate-limit`. -.. _mod-rrl_table-size: +The specific prefixes and multipliers, which might be adjusted in the future, are +for IPv6 /128: 1, /64: 2, /56: 3, /48: 4, /32: 64; +for IPv4 /32: 1, /24: 32, /20: 256, /18: 768. -table-size -.......... +With each host/network, a counter of unrestricted responses is associated; +if the counter would exceed its capacity, it is not incremented and the response is restricted. +Counters use exponential decay for lowering their values, +i.e. they are lowered by a constant fraction of their value each millisecond. +The specified rate limit is reached, when the number of queries is the same every millisecond; +sending many queries once a second or even a larger timespan leads to a more strict limiting. + +*Default:* ``20`` + +.. _mod-rrl_instant-limit: + +instant-limit +............. + +Maximal allowed number of queries at a single point in time from a single IPv6 or IPv4 address. +The limits for prefixes use the same multipliers as for :ref:`mod-rrl_rate-limit`. -Size of the hash table in a number of buckets. The larger the hash table, the lesser -the probability of a hash collision, but at the expense of additional memory costs. -Each bucket is estimated roughly to 32 bytes. The size should be selected as -a reasonably large prime due to better hash function distribution properties. -Hash table is internally chained and works well up to a fill rate of 90 %, general -rule of thumb is to select a prime near 1.2 * maximum_qps. +This limit is reached when many queries come from a new host/network, +or after a longer time of inactivity. -*Default:* ``393241`` +The :ref:`mod-rrl_instant-limit` sets the actual capacity of each counter of responses, +and together with the :ref:`mod-rrl_rate-limit` they set the fraction by which the counter +is periodically lowered. +The :ref:`mod-rrl_instant-limit` may be at least :ref:`mod-rrl_rate-limit` **/ 1000**, at which point the +counters are zeroed each millisecond. + +*Default:* ``50`` .. _mod-rrl_slip: @@ -121,6 +153,49 @@ noting, that some responses can't be truncated (e.g. SERVFAIL). *Default:* ``1`` +.. _mod-rrl_time-rate-limit: + +time-rate-limit +............... + +This limit works similarly to :ref:`mod-rrl_rate-limit` but considers the time +consumed (in microseconds) by the remote over non-UDP transport protocols. + +*Default:* ``4000`` (microseconds) + +.. _mod-rrl_time-instant-limit: + +time-instant-limit +.................. + +This limit works similarly to :ref:`mod-rrl_instant-limit` but considers the time +consumed (in microseconds) by the remote over non-UDP transport protocols. + +*Default:* ``5000`` (microseconds) + +.. _mod-rrl_table-size: + +table-size +.......... + +Maximal number of stored hosts/networks with their counters. +The data structure tries to store only the most frequent sources, +so it is safe to set it according to the expected maximal number of limited ones. + +Use `1.4 * maximum_qps / rate-limit`, +where `maximum_qps` is the number of queries which can be handled by the server per second. +There is at most `maximum_qps / rate-limit` limited hosts; +larger networks have higher limits and so require only a fraction of the value (handled by the `1.4` multiplier). +The value will be rounded up to the nearest power of two. + +The same table size is used for both counting-based and time-based limiting; +the maximum number of time-limited hosts is expected to be lower, so it's not typically needed to be considered. +There is at most `1 000 000 * #cpus / time-rate-limit` of them. + +The memory occupied by one table structure is `8 * table-size B`. + +*Default:* ``524288`` + .. _mod-rrl_whitelist: whitelist @@ -131,3 +206,31 @@ or network ranges to exempt from rate limiting. Empty list means that no incoming connection will be white-listed. *Default:* not set + +.. _mod-rrl_log-period: + +log-period +.......... + +Minimal time in milliseconds between two log messages, +or zero to disable logging. + +If a response is limited, the address and the prefix on which it was blocked is logged +and logging is disabled for the `log-period` milliseconds. +As long as limiting is needed, one source is logged each period +and sources with more blocked queries have greater probability to be chosen. + +The approach is used by counting-based and time-based limiting separately, +so you can expect one message per `log-period` from each of them. + +*Default:* ``0`` (disabled) + +.. _mod-rrl_dry-run: + +dry-run +....... + +If enabled, the module doesn't alter any response. Only query classification +is performed with possible statistics counter incrementation. + +*Default:* ``off`` diff --git a/src/knot/modules/stats/stats.c b/src/knot/modules/stats/stats.c index 26262ac..c5b797b 100644 --- a/src/knot/modules/stats/stats.c +++ b/src/knot/modules/stats/stats.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -118,9 +118,11 @@ enum { PROTOCOL_UDP4 = 0, PROTOCOL_TCP4, PROTOCOL_QUIC4, + PROTOCOL_TLS4, PROTOCOL_UDP6, PROTOCOL_TCP6, PROTOCOL_QUIC6, + PROTOCOL_TLS6, PROTOCOL_UDP4_XDP, PROTOCOL_TCP4_XDP, PROTOCOL_QUIC4_XDP, @@ -136,9 +138,11 @@ static char *protocol_to_str(uint32_t idx, uint32_t count) case PROTOCOL_UDP4: return strdup("udp4"); case PROTOCOL_TCP4: return strdup("tcp4"); case PROTOCOL_QUIC4: return strdup("quic4"); + case PROTOCOL_TLS4: return strdup("tls4"); case PROTOCOL_UDP6: return strdup("udp6"); case PROTOCOL_TCP6: return strdup("tcp6"); case PROTOCOL_QUIC6: return strdup("quic6"); + case PROTOCOL_TLS6: return strdup("tls6"); case PROTOCOL_UDP4_XDP: return strdup("udp4-xdp"); case PROTOCOL_TCP4_XDP: return strdup("tcp4-xdp"); case PROTOCOL_QUIC4_XDP: return strdup("quic4-xdp"); @@ -521,6 +525,10 @@ static knotd_state_t update_counters(knotd_state_t state, knot_pkt_t *pkt, knotd_mod_stats_incr(mod, tid, CTR_PROTOCOL, PROTOCOL_QUIC4, 1); } + } else if (qdata->params->proto == KNOTD_QUERY_PROTO_TLS) { + assert(!xdp); + knotd_mod_stats_incr(mod, tid, CTR_PROTOCOL, + PROTOCOL_TLS4, 1); } else { if (xdp) { knotd_mod_stats_incr(mod, tid, CTR_PROTOCOL, @@ -547,6 +555,10 @@ static knotd_state_t update_counters(knotd_state_t state, knot_pkt_t *pkt, knotd_mod_stats_incr(mod, tid, CTR_PROTOCOL, PROTOCOL_QUIC6, 1); } + } else if (qdata->params->proto == KNOTD_QUERY_PROTO_TLS) { + assert(!xdp); + knotd_mod_stats_incr(mod, tid, CTR_PROTOCOL, + PROTOCOL_TLS6, 1); } else { if (xdp) { knotd_mod_stats_incr(mod, tid, CTR_PROTOCOL, diff --git a/src/knot/modules/stats/stats.rst b/src/knot/modules/stats/stats.rst index 8acf1aa..71cf87a 100644 --- a/src/knot/modules/stats/stats.rst +++ b/src/knot/modules/stats/stats.rst @@ -73,9 +73,11 @@ If enabled, all incoming requests are counted by the network protocol: * udp4 - UDP over IPv4 * tcp4 - TCP over IPv4 * quic4 - QUIC over IPv4 +* tls4 - TLS over IPv4 * udp6 - UDP over IPv6 * tcp6 - TCP over IPv6 * quic6 - QUIC over IPv6 +* tls6 - TLS over IPv6 * udp4-xdp - UDP over IPv4 through XDP * tcp4-xdp - TCP over IPv4 through XDP * quic4-xdp - QUIC over IPv4 through XDP diff --git a/src/knot/nameserver/axfr.c b/src/knot/nameserver/axfr.c index dcd62e9..cd9ee32 100644 --- a/src/knot/nameserver/axfr.c +++ b/src/knot/nameserver/axfr.c @@ -121,14 +121,14 @@ static void axfr_answer_finished(knotd_qdata_t *qdata, knot_pkt_t *pkt, int stat xfr_stats_add(&xfr->stats, pkt->size); xfr_stats_end(&xfr->stats); xfr_log_finished(ZONE_NAME(qdata), LOG_OPERATION_AXFR, LOG_DIRECTION_OUT, - REMOTE(qdata), PROTO(qdata), KEY(qdata), &xfr->stats); + REMOTE(qdata), PROTO(qdata), KEY(qdata), "", &xfr->stats); break; default: break; } } -static int axfr_query_check(knotd_qdata_t *qdata) +static knot_layer_state_t axfr_query_check(knotd_qdata_t *qdata) { NS_NEED_ZONE(qdata, KNOT_RCODE_NOTAUTH); NS_NEED_AUTH(qdata, ACL_ACTION_TRANSFER); @@ -187,7 +187,7 @@ static int axfr_query_init(knotd_qdata_t *qdata) return KNOT_EOK; } -int axfr_process_query(knot_pkt_t *pkt, knotd_qdata_t *qdata) +knot_layer_state_t axfr_process_query(knot_pkt_t *pkt, knotd_qdata_t *qdata) { if (pkt == NULL || qdata == NULL) { return KNOT_STATE_FAIL; diff --git a/src/knot/nameserver/axfr.h b/src/knot/nameserver/axfr.h index 81fcad8..25c5f1c 100644 --- a/src/knot/nameserver/axfr.h +++ b/src/knot/nameserver/axfr.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -21,7 +21,5 @@ /*! * \brief Process an AXFR query message. - * - * \return KNOT_STATE_* processing states */ -int axfr_process_query(knot_pkt_t *pkt, knotd_qdata_t *qdata); +knot_layer_state_t axfr_process_query(knot_pkt_t *pkt, knotd_qdata_t *qdata); diff --git a/src/knot/nameserver/internet.c b/src/knot/nameserver/internet.c index 51bde97..034fd26 100644 --- a/src/knot/nameserver/internet.c +++ b/src/knot/nameserver/internet.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -286,7 +286,7 @@ static int put_additional(knot_pkt_t *pkt, const knot_rrset_t *rr, return ret; } -static int follow_cname(knot_pkt_t *pkt, uint16_t rrtype, knotd_qdata_t *qdata) +static knotd_in_state_t follow_cname(knot_pkt_t *pkt, uint16_t rrtype, knotd_qdata_t *qdata) { /* CNAME chain processing limit. */ if (++qdata->extra->cname_chain > CNAME_CHAIN_MAX) { @@ -369,7 +369,7 @@ static int follow_cname(knot_pkt_t *pkt, uint16_t rrtype, knotd_qdata_t *qdata) return KNOTD_IN_STATE_FOLLOW; } -static int name_found(knot_pkt_t *pkt, knotd_qdata_t *qdata) +static knotd_in_state_t name_found(knot_pkt_t *pkt, knotd_qdata_t *qdata) { uint16_t qtype = knot_pkt_qtype(pkt); @@ -406,7 +406,7 @@ static int name_found(knot_pkt_t *pkt, knotd_qdata_t *qdata) } } -static int name_not_found(knot_pkt_t *pkt, knotd_qdata_t *qdata) +static knotd_in_state_t name_not_found(knot_pkt_t *pkt, knotd_qdata_t *qdata) { /* Name is covered by wildcard. */ if (qdata->extra->encloser->flags & NODE_FLAGS_WILDCARD_CHILD) { @@ -419,7 +419,7 @@ static int name_not_found(knot_pkt_t *pkt, knotd_qdata_t *qdata) assert(qdata->extra->node != NULL); /* Follow expanded wildcard. */ - int next_state = name_found(pkt, qdata); + knotd_in_state_t next_state = name_found(pkt, qdata); /* Put to wildcard node list. */ if (wildcard_has_visited(qdata, wildcard_node)) { @@ -456,7 +456,8 @@ static int name_not_found(knot_pkt_t *pkt, knotd_qdata_t *qdata) return KNOTD_IN_STATE_MISS; } -static int solve_name(int state, knot_pkt_t *pkt, knotd_qdata_t *qdata) +static knotd_in_state_t solve_name(knotd_in_state_t state, knot_pkt_t *pkt, + knotd_qdata_t *qdata) { int ret = zone_contents_find_dname(qdata->extra->contents, qdata->name, &qdata->extra->node, &qdata->extra->encloser, @@ -475,7 +476,8 @@ static int solve_name(int state, knot_pkt_t *pkt, knotd_qdata_t *qdata) } } -static int solve_answer(int state, knot_pkt_t *pkt, knotd_qdata_t *qdata, void *ctx) +static knotd_in_state_t solve_answer(knotd_in_state_t state, knot_pkt_t *pkt, + knotd_qdata_t *qdata, void *ctx) { int old_state = state; @@ -506,7 +508,8 @@ static int solve_answer(int state, knot_pkt_t *pkt, knotd_qdata_t *qdata, void * return state; } -static int solve_answer_dnssec(int state, knot_pkt_t *pkt, knotd_qdata_t *qdata, void *ctx) +static knotd_in_state_t solve_answer_dnssec(knotd_in_state_t state, knot_pkt_t *pkt, + knotd_qdata_t *qdata, void *ctx) { /* RFC4035, section 3.1 RRSIGs for RRs in ANSWER are mandatory. */ int ret = nsec_append_rrsigs(pkt, qdata, false); @@ -517,7 +520,8 @@ static int solve_answer_dnssec(int state, knot_pkt_t *pkt, knotd_qdata_t *qdata, } } -static int solve_authority(int state, knot_pkt_t *pkt, knotd_qdata_t *qdata, void *ctx) +static knotd_in_state_t solve_authority(knotd_in_state_t state, knot_pkt_t *pkt, + knotd_qdata_t *qdata, void *ctx) { int ret = KNOT_ERROR; const zone_contents_t *zone_contents = qdata->extra->contents; @@ -554,7 +558,8 @@ static int solve_authority(int state, knot_pkt_t *pkt, knotd_qdata_t *qdata, voi } } -static int solve_authority_dnssec(int state, knot_pkt_t *pkt, knotd_qdata_t *qdata, void *ctx) +static knotd_in_state_t solve_authority_dnssec(knotd_in_state_t state, knot_pkt_t *pkt, + knotd_qdata_t *qdata, void *ctx) { int ret = KNOT_ERROR; @@ -591,8 +596,8 @@ static int solve_authority_dnssec(int state, knot_pkt_t *pkt, knotd_qdata_t *qda } } -static int solve_additional(int state, knot_pkt_t *pkt, knotd_qdata_t *qdata, - void *ctx) +static knotd_in_state_t solve_additional(knotd_in_state_t state, knot_pkt_t *pkt, + knotd_qdata_t *qdata, void *ctx) { int ret = KNOT_EOK, rrset_count = pkt->rrset_count; @@ -621,7 +626,8 @@ static int solve_additional(int state, knot_pkt_t *pkt, knotd_qdata_t *qdata, } } -static int solve_additional_dnssec(int state, knot_pkt_t *pkt, knotd_qdata_t *qdata, void *ctx) +static knotd_in_state_t solve_additional_dnssec(knotd_in_state_t state, knot_pkt_t *pkt, + knotd_qdata_t *qdata, void *ctx) { /* RFC4035, section 3.1 RRSIGs for RRs in ADDITIONAL are optional. */ int ret = nsec_append_rrsigs(pkt, qdata, true); @@ -641,9 +647,9 @@ static int solve_additional_dnssec(int state, knot_pkt_t *pkt, knotd_qdata_t *qd return KNOT_STATE_FAIL; \ } -static int answer_query(knot_pkt_t *pkt, knotd_qdata_t *qdata) +static knot_layer_state_t answer_query(knot_pkt_t *pkt, knotd_qdata_t *qdata) { - int state = KNOTD_IN_STATE_BEGIN; + knotd_in_state_t state = KNOTD_IN_STATE_BEGIN; struct query_plan *plan = qdata->extra->zone->query_plan; struct query_step *step; @@ -652,7 +658,8 @@ static int answer_query(knot_pkt_t *pkt, knotd_qdata_t *qdata) /* Resolve PREANSWER. */ if (plan != NULL) { WALK_LIST(step, plan->stage[KNOTD_STAGE_PREANSWER]) { - SOLVE_STEP(step->process, state, step->ctx); + assert(step->type == QUERY_HOOK_TYPE_IN); + SOLVE_STEP(step->in_hook, state, step->ctx); } } @@ -664,7 +671,8 @@ static int answer_query(knot_pkt_t *pkt, knotd_qdata_t *qdata) } if (plan != NULL) { WALK_LIST(step, plan->stage[KNOTD_STAGE_ANSWER]) { - SOLVE_STEP(step->process, state, step->ctx); + assert(step->type == QUERY_HOOK_TYPE_IN); + SOLVE_STEP(step->in_hook, state, step->ctx); } } @@ -676,7 +684,8 @@ static int answer_query(knot_pkt_t *pkt, knotd_qdata_t *qdata) } if (plan != NULL) { WALK_LIST(step, plan->stage[KNOTD_STAGE_AUTHORITY]) { - SOLVE_STEP(step->process, state, step->ctx); + assert(step->type == QUERY_HOOK_TYPE_IN); + SOLVE_STEP(step->in_hook, state, step->ctx); } } @@ -688,7 +697,8 @@ static int answer_query(knot_pkt_t *pkt, knotd_qdata_t *qdata) } if (plan != NULL) { WALK_LIST(step, plan->stage[KNOTD_STAGE_ADDITIONAL]) { - SOLVE_STEP(step->process, state, step->ctx); + assert(step->type == QUERY_HOOK_TYPE_IN); + SOLVE_STEP(step->in_hook, state, step->ctx); } } @@ -698,7 +708,7 @@ static int answer_query(knot_pkt_t *pkt, knotd_qdata_t *qdata) return KNOT_STATE_DONE; } -int internet_process_query(knot_pkt_t *pkt, knotd_qdata_t *qdata) +knot_layer_state_t internet_process_query(knot_pkt_t *pkt, knotd_qdata_t *qdata) { if (pkt == NULL || qdata == NULL) { return KNOT_STATE_FAIL; diff --git a/src/knot/nameserver/internet.h b/src/knot/nameserver/internet.h index 52afe62..bb6927d 100644 --- a/src/knot/nameserver/internet.h +++ b/src/knot/nameserver/internet.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -25,11 +25,8 @@ /*! * \brief Answer query from an IN class zone. - * - * \retval KNOT_STATE_FAIL if it encountered an error. - * \retval KNOT_STATE_DONE if finished. */ -int internet_process_query(knot_pkt_t *pkt, knotd_qdata_t *qdata); +knot_layer_state_t internet_process_query(knot_pkt_t *pkt, knotd_qdata_t *qdata); /*! \brief Require given QUERY TYPE or return error code. */ #define NS_NEED_QTYPE(qdata, qtype_want, error_rcode) \ @@ -68,12 +65,6 @@ int internet_process_query(knot_pkt_t *pkt, knotd_qdata_t *qdata); if (!process_query_acl_check(conf(), (action), (qdata)) || \ process_query_verify(qdata) != KNOT_EOK) { \ return KNOT_STATE_FAIL; \ - } - -/*! \brief Require the zone not to be frozen. */ -#define NS_NEED_NOT_FROZEN(qdata) \ - if ((qdata)->extra->zone->events.ufrozen) { \ - (qdata)->rcode = KNOT_RCODE_REFUSED; \ - (qdata)->rcode_ede = KNOT_EDNS_EDE_NOT_READY; \ - return KNOT_STATE_FAIL; \ + } else { \ + qdata->params->flags |= KNOTD_QUERY_FLAG_AUTHORIZED; \ } diff --git a/src/knot/nameserver/ixfr.c b/src/knot/nameserver/ixfr.c index b57759c..c0e17ea 100644 --- a/src/knot/nameserver/ixfr.c +++ b/src/knot/nameserver/ixfr.c @@ -130,7 +130,7 @@ static int ixfr_load_chsets(journal_read_t **journal_read, zone_t *zone, return journal_read_begin(zone_journal(zone), false, serial_from, journal_read); } -static int ixfr_query_check(knotd_qdata_t *qdata) +static knot_layer_state_t ixfr_query_check(knotd_qdata_t *qdata) { NS_NEED_ZONE(qdata, KNOT_RCODE_NOTAUTH); NS_NEED_AUTH(qdata, ACL_ACTION_TRANSFER); @@ -174,7 +174,7 @@ static void ixfr_answer_finished(knotd_qdata_t *qdata, knot_pkt_t *pkt, int stat xfr_stats_add(&xfr->stats, pkt->size); xfr_stats_end(&xfr->stats); xfr_log_finished(ZONE_NAME(qdata), LOG_OPERATION_IXFR, LOG_DIRECTION_OUT, - REMOTE(qdata), PROTO(qdata), KEY(qdata), &xfr->stats); + REMOTE(qdata), PROTO(qdata), KEY(qdata), "", &xfr->stats); break; default: break; @@ -245,13 +245,13 @@ static int ixfr_answer_init(knotd_qdata_t *qdata, uint32_t *serial_from) return KNOT_EOK; } -static int ixfr_answer_soa(knot_pkt_t *pkt, knotd_qdata_t *qdata) +static knot_layer_state_t ixfr_answer_soa(knot_pkt_t *pkt, knotd_qdata_t *qdata) { assert(pkt); assert(qdata); /* Check query. */ - int state = ixfr_query_check(qdata); + knot_layer_state_t state = ixfr_query_check(qdata); if (state == KNOT_STATE_FAIL) { return state; /* Malformed query. */ } @@ -277,7 +277,7 @@ static int ixfr_answer_soa(knot_pkt_t *pkt, knotd_qdata_t *qdata) return KNOT_STATE_DONE; } -int ixfr_process_query(knot_pkt_t *pkt, knotd_qdata_t *qdata) +knot_layer_state_t ixfr_process_query(knot_pkt_t *pkt, knotd_qdata_t *qdata) { if (pkt == NULL || qdata == NULL) { return KNOT_STATE_FAIL; diff --git a/src/knot/nameserver/ixfr.h b/src/knot/nameserver/ixfr.h index 3012be1..91ce750 100644 --- a/src/knot/nameserver/ixfr.h +++ b/src/knot/nameserver/ixfr.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -55,9 +55,5 @@ struct ixfr_proc { /*! * \brief IXFR query processing module. - * - * \retval PRODUCE if it has an answer, but not yet finished. - * \retval FAIL if it encountered an error. - * \retval DONE if finished. */ -int ixfr_process_query(knot_pkt_t *pkt, knotd_qdata_t *qdata); +knot_layer_state_t ixfr_process_query(knot_pkt_t *pkt, knotd_qdata_t *qdata); diff --git a/src/knot/nameserver/log.h b/src/knot/nameserver/log.h index 5a5d5f0..373d65a 100644 --- a/src/knot/nameserver/log.h +++ b/src/knot/nameserver/log.h @@ -81,6 +81,8 @@ static inline const char *log_conn_info(knotd_query_proto_t proto, bool pool) return pool ? " TCP/pool" : " TCP"; case KNOTD_QUERY_PROTO_QUIC: return pool ? " QUIC/0-RTT" : " QUIC"; + case KNOTD_QUERY_PROTO_TLS: + return " TLS"; default: return ""; } diff --git a/src/knot/nameserver/notify.c b/src/knot/nameserver/notify.c index eaa305a..5b1593f 100644 --- a/src/knot/nameserver/notify.c +++ b/src/knot/nameserver/notify.c @@ -29,7 +29,7 @@ LOG_DIRECTION_IN, (qdata)->params->remote, (qdata)->params->proto, \ false, (qdata)->sign.tsig_key.name, fmt) -static int notify_check_query(knotd_qdata_t *qdata) +static knot_layer_state_t notify_check_query(knotd_qdata_t *qdata) { NS_NEED_ZONE(qdata, KNOT_RCODE_NOTAUTH); NS_NEED_AUTH(qdata, ACL_ACTION_NOTIFY); @@ -39,14 +39,14 @@ static int notify_check_query(knotd_qdata_t *qdata) return KNOT_STATE_DONE; } -int notify_process_query(knot_pkt_t *pkt, knotd_qdata_t *qdata) +knot_layer_state_t notify_process_query(knot_pkt_t *pkt, knotd_qdata_t *qdata) { if (pkt == NULL || qdata == NULL) { return KNOT_STATE_FAIL; } /* Validate notification query. */ - int state = notify_check_query(qdata); + knot_layer_state_t state = notify_check_query(qdata); if (state == KNOT_STATE_FAIL) { switch (qdata->rcode) { case KNOT_RCODE_NOTAUTH: /* Not authorized, already logged. */ diff --git a/src/knot/nameserver/notify.h b/src/knot/nameserver/notify.h index d0bff14..0e60b58 100644 --- a/src/knot/nameserver/notify.h +++ b/src/knot/nameserver/notify.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -21,8 +21,5 @@ /*! * \brief Answer IN class zone NOTIFY message (RFC1996). - * - * \retval FAIL if it encountered an error. - * \retval DONE if finished. */ -int notify_process_query(knot_pkt_t *pkt, knotd_qdata_t *qdata); +knot_layer_state_t notify_process_query(knot_pkt_t *pkt, knotd_qdata_t *qdata); diff --git a/src/knot/nameserver/nsec_proofs.c b/src/knot/nameserver/nsec_proofs.c index 71944b1..b67566c 100644 --- a/src/knot/nameserver/nsec_proofs.c +++ b/src/knot/nameserver/nsec_proofs.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -121,11 +121,11 @@ static const knot_dname_t *get_next_closer(const knot_dname_t *closest_encloser, size_t ce_labels = knot_dname_labels(closest_encloser, NULL); size_t qname_labels = knot_dname_labels(name, NULL); for (int i = 0; i < (qname_labels - ce_labels - 1); ++i) { - name = knot_wire_next_label(name, NULL); + name = knot_dname_next_label(name); } // the common labels should match - assert(knot_dname_is_equal(knot_wire_next_label(name, NULL), closest_encloser)); + assert(knot_dname_is_equal(knot_dname_next_label(name), closest_encloser)); return name; } diff --git a/src/knot/nameserver/process_query.c b/src/knot/nameserver/process_query.c index 00ec001..beced84 100644 --- a/src/knot/nameserver/process_query.c +++ b/src/knot/nameserver/process_query.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -30,9 +30,9 @@ #include "knot/nameserver/notify.h" #include "knot/server/server.h" #include "libknot/libknot.h" -#ifdef ENABLE_QUIC -#include "libknot/quic/quic.h" -#endif // ENABLE_QUIC +#include "libknot/quic/quic_conn.h" +#include "libknot/quic/tls_common.h" +#include "libknot/quic/tls.h" #include "contrib/base64.h" #include "contrib/macros.h" #include "contrib/mempattern.h" @@ -147,7 +147,7 @@ static int process_query_in(knot_layer_t *ctx, knot_pkt_t *pkt) /*! * \brief Create a response for a given query in the INTERNET class. */ -static int query_internet(knot_pkt_t *pkt, knot_layer_t *ctx) +static knot_layer_state_t query_internet(knot_pkt_t *pkt, knot_layer_t *ctx) { knotd_qdata_t *data = QUERY_DATA(ctx); @@ -167,7 +167,7 @@ static int query_internet(knot_pkt_t *pkt, knot_layer_t *ctx) /*! * \brief Create a response for a given query in the CHAOS class. */ -static int query_chaos(knot_pkt_t *pkt, knot_layer_t *ctx) +static knot_layer_state_t query_chaos(knot_pkt_t *pkt, knot_layer_t *ctx) { knotd_qdata_t *data = QUERY_DATA(ctx); @@ -203,7 +203,7 @@ static zone_t *answer_zone_find(const knot_pkt_t *query, knot_zonedb_t *zonedb) * records are only present in a parent zone. */ if (qtype == KNOT_RRTYPE_DS) { - const knot_dname_t *parent = knot_wire_next_label(qname, NULL); + const knot_dname_t *parent = knot_dname_next_label(qname); zone = knot_zonedb_find_suffix(zonedb, parent); /* If zone does not exist, search for its parent zone, this will later result to NODATA answer. */ @@ -364,6 +364,7 @@ static int answer_edns_put(knot_pkt_t *resp, knotd_qdata_t *qdata) if (knot_pkt_edns_option(qdata->query, KNOT_EDNS_OPTION_EXPIRE) != NULL && qdata->extra->contents != NULL && !qdata->extra->zone->is_catalog_flag) { int64_t timer = qdata->extra->zone->timers.next_expire; + timer = knot_time_min(timer, qdata->extra->contents->dnssec_expire); // NOOP if zero timer = (timer == 0 ? zone_soa_expire(qdata->extra->zone) : timer - time(NULL)); timer = MAX(timer, 0); uint32_t timer_be; @@ -389,8 +390,8 @@ static int answer_edns_put(knot_pkt_t *resp, knotd_qdata_t *qdata) return ret; } - /* Align the response if QUIC with EDNS. */ - if (qdata->params->proto == KNOTD_QUERY_PROTO_QUIC) { + /* Align the response if QUIC or TLS with EDNS. */ + if (qdata->params->proto == KNOTD_QUERY_PROTO_QUIC || qdata->params->proto == KNOTD_QUERY_PROTO_TLS) { int pad_len = knot_pkt_default_padding_size(resp, &qdata->opt_rr); if (pad_len > -1) { ret = knot_edns_reserve_option(&qdata->opt_rr, KNOT_EDNS_OPTION_PADDING, @@ -506,7 +507,7 @@ static void set_rcode_to_packet(knot_pkt_t *pkt, knotd_qdata_t *qdata) knot_wire_set_rcode(pkt->wire, KNOT_EDNS_RCODE_LO(qdata->rcode)); } -static int process_query_err(knot_layer_t *ctx, knot_pkt_t *pkt) +static knot_layer_state_t process_query_err(knot_layer_t *ctx, knot_pkt_t *pkt) { assert(ctx && pkt); @@ -552,7 +553,8 @@ static int process_query_err(knot_layer_t *ctx, knot_pkt_t *pkt) #define PROCESS_BEGIN(plan, step, next_state, qdata) \ if (plan != NULL) { \ WALK_LIST(step, plan->stage[KNOTD_STAGE_BEGIN]) { \ - next_state = step->process(next_state, pkt, qdata, step->ctx); \ + assert(step->type == QUERY_HOOK_TYPE_GENERAL); \ + next_state = step->general_hook(next_state, pkt, qdata, step->ctx); \ if (next_state == KNOT_STATE_FAIL) { \ goto finish; \ } \ @@ -562,7 +564,8 @@ static int process_query_err(knot_layer_t *ctx, knot_pkt_t *pkt) #define PROCESS_END(plan, step, next_state, qdata) \ if (plan != NULL) { \ WALK_LIST(step, plan->stage[KNOTD_STAGE_END]) { \ - next_state = step->process(next_state, pkt, qdata, step->ctx); \ + assert(step->type == QUERY_HOOK_TYPE_GENERAL); \ + next_state = step->general_hook(next_state, pkt, qdata, step->ctx); \ if (next_state == KNOT_STATE_FAIL) { \ next_state = process_query_err(ctx, pkt); \ } \ @@ -705,43 +708,53 @@ bool process_query_acl_check(conf_t *conf, acl_action_t action, bool automatic = false; bool allowed = false; + struct gnutls_session_int *tls_session; + switch (qdata->params->proto) { + case KNOTD_QUERY_PROTO_QUIC: tls_session = qdata->params->quic_conn->tls_session; break; + case KNOTD_QUERY_PROTO_TLS: tls_session = qdata->params->tls_conn->session; break; + default: tls_session = NULL; + } + if (action != ACL_ACTION_UPDATE) { // ACL_ACTION_QUERY is used for SOA/refresh query. assert(action == ACL_ACTION_QUERY || action == ACL_ACTION_NOTIFY || action == ACL_ACTION_TRANSFER); const yp_name_t *item = (action == ACL_ACTION_NOTIFY) ? C_MASTER : C_NOTIFY; conf_val_t rmts = conf_zone_get(conf, item, zone_name); - allowed = rmt_allowed(conf, &rmts, query_source, &tsig, - qdata->params->quic_conn); + allowed = rmt_allowed(conf, &rmts, query_source, &tsig, tls_session); automatic = allowed; } if (!allowed) { conf_val_t acl = conf_zone_get(conf, C_ACL, zone_name); allowed = acl_allowed(conf, &acl, action, query_source, &tsig, - zone_name, query, qdata->params->quic_conn); + zone_name, query, tls_session); } if (log_enabled_debug()) { int pin_size = 0; -#ifdef ENABLE_QUIC - uint8_t bin_pin[KNOT_QUIC_PIN_LEN], pin[2 * KNOT_QUIC_PIN_LEN]; + uint8_t bin_pin[KNOT_TLS_PIN_LEN], pin[2 * KNOT_TLS_PIN_LEN]; size_t bin_pin_size = sizeof(bin_pin); - knot_quic_conn_pin(qdata->params->quic_conn, bin_pin, &bin_pin_size, false); + knot_tls_pin(tls_session, bin_pin, &bin_pin_size, false); if (bin_pin_size > 0) { pin_size = knot_base64_encode(bin_pin, bin_pin_size, pin, sizeof(pin)); } -#else - uint8_t pin[1]; -#endif // ENABLE_QUIC + + const char *proto_str; + switch (qdata->params->proto) { + case KNOTD_QUERY_PROTO_UDP: proto_str = " UDP"; break; + case KNOTD_QUERY_PROTO_TCP: proto_str = " TCP"; break; + case KNOTD_QUERY_PROTO_QUIC: proto_str = " QUIC"; break; + case KNOTD_QUERY_PROTO_TLS: proto_str = " TLS"; break; + default: proto_str = ""; + } log_zone_debug(zone_name, "ACL, %s, action %s, remote %s%s%s%s%s%.*s%s", allowed ? "allowed" : "denied", (act != NULL) ? act->name : "query", - addr_str, + addr_str, proto_str, (key_name[0] != '\0') ? ", key " : "", (key_name[0] != '\0') ? key_name : "", - (qdata->params->proto == KNOTD_QUERY_PROTO_QUIC) ? ", QUIC" : "", (pin_size > 0) ? " cert-key " : "", (pin_size > 0) ? pin_size : 0, (pin_size > 0) ? (const char *)pin : "", @@ -994,6 +1007,30 @@ int process_query_put_rr(knot_pkt_t *pkt, knotd_qdata_t *qdata, return ret; } +knotd_proto_state_t process_query_proto(knotd_qdata_params_t *params, + const knotd_stage_t stage) +{ + assert(params); + assert(stage == KNOTD_STAGE_PROTO_BEGIN || stage == KNOTD_STAGE_PROTO_END); + + knotd_proto_state_t state = KNOTD_PROTO_STATE_PASS; + + rcu_read_lock(); + + struct query_plan *plan = conf()->query_plan; + if (plan != NULL) { + struct query_step *step; + WALK_LIST(step, plan->stage[stage]) { + assert(step->type == QUERY_HOOK_TYPE_PROTO); + state = step->proto_hook(state, params, step->ctx); + } + } + + rcu_read_unlock(); + + return state; +} + /*! \brief Module implementation. */ const knot_layer_api_t *process_query_layer(void) { diff --git a/src/knot/nameserver/process_query.h b/src/knot/nameserver/process_query.h index 42e66be..c005b58 100644 --- a/src/knot/nameserver/process_query.h +++ b/src/knot/nameserver/process_query.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -106,3 +106,14 @@ int process_query_sign_response(knot_pkt_t *pkt, knotd_qdata_t *qdata); int process_query_put_rr(knot_pkt_t *pkt, knotd_qdata_t *qdata, const knot_rrset_t *rr, const knot_rrset_t *rrsigs, uint16_t compr_hint, uint32_t flags); + +/*! + * \brief Processes all global module protocol callbacks at given stage. + * + * \param params Query processing parameters. + * \param stage Processing stage (KNOTD_STAGE_PROTO_BEGIN or KNOTD_STAGE_PROTO_END). + * + * \return Resulting state. + */ +knotd_proto_state_t process_query_proto(knotd_qdata_params_t *params, + const knotd_stage_t stage); diff --git a/src/knot/nameserver/query_module.c b/src/knot/nameserver/query_module.c index f02ee1b..0708b17 100644 --- a/src/knot/nameserver/query_module.c +++ b/src/knot/nameserver/query_module.c @@ -32,17 +32,6 @@ #include "knot/nameserver/query_module.h" #include "knot/nameserver/process_query.h" -#ifdef HAVE_ATOMIC - #define ATOMIC_ADD(dst, val) __atomic_add_fetch(&(dst), (val), __ATOMIC_RELAXED) - #define ATOMIC_SUB(dst, val) __atomic_sub_fetch(&(dst), (val), __ATOMIC_RELAXED) - #define ATOMIC_SET(dst, val) __atomic_store_n(&(dst), (val), __ATOMIC_RELAXED) -#else - #warning "Statistics data can be inaccurate" - #define ATOMIC_ADD(dst, val) ((dst) += (val)) - #define ATOMIC_SUB(dst, val) ((dst) -= (val)) - #define ATOMIC_SET(dst, val) ((dst) = (val)) -#endif - _public_ int knotd_conf_check_ref(knotd_conf_check_args_t *args) { @@ -79,30 +68,31 @@ void query_plan_free(struct query_plan *plan) free(plan); } -static struct query_step *make_step(query_step_process_f process, void *ctx) +int query_plan_step(struct query_plan *plan, knotd_stage_t stage, + query_hook_type_t type, void *hook, void *ctx) { - struct query_step *step = calloc(1, sizeof(struct query_step)); + struct query_step *step = calloc(1, sizeof(*step)); if (step == NULL) { - return NULL; + return KNOT_ENOMEM; } - step->process = process; + step->type = type; + step->general_hook = hook; step->ctx = ctx; - return step; + add_tail(&plan->stage[stage], &step->node); + + return KNOT_EOK; } -int query_plan_step(struct query_plan *plan, knotd_stage_t stage, - query_step_process_f process, void *ctx) +_public_ +int knotd_mod_proto_hook(knotd_mod_t *mod, knotd_stage_t stage, knotd_mod_proto_hook_f hook) { - struct query_step *step = make_step(process, ctx); - if (step == NULL) { - return KNOT_ENOMEM; + if (stage != KNOTD_STAGE_PROTO_BEGIN && stage != KNOTD_STAGE_PROTO_END) { + return KNOT_EINVAL; } - add_tail(&plan->stage[stage], &step->node); - - return KNOT_EOK; + return query_plan_step(mod->plan, stage, QUERY_HOOK_TYPE_PROTO, hook, mod); } _public_ @@ -112,17 +102,18 @@ int knotd_mod_hook(knotd_mod_t *mod, knotd_stage_t stage, knotd_mod_hook_f hook) return KNOT_EINVAL; } - return query_plan_step(mod->plan, stage, hook, mod); + return query_plan_step(mod->plan, stage, QUERY_HOOK_TYPE_GENERAL, hook, mod); } _public_ int knotd_mod_in_hook(knotd_mod_t *mod, knotd_stage_t stage, knotd_mod_in_hook_f hook) { - if (stage == KNOTD_STAGE_BEGIN || stage == KNOTD_STAGE_END) { + if (stage != KNOTD_STAGE_PREANSWER && stage != KNOTD_STAGE_ANSWER && + stage != KNOTD_STAGE_AUTHORITY && stage != KNOTD_STAGE_ADDITIONAL) { return KNOT_EINVAL; } - return query_plan_step(mod->plan, stage, hook, mod); + return query_plan_step(mod->plan, stage, QUERY_HOOK_TYPE_IN, hook, mod); } knotd_mod_t *query_module_open(conf_t *conf, server_t *server, conf_mod_id_t *mod_id, @@ -313,8 +304,8 @@ int knotd_mod_stats_add(knotd_mod_t *mod, const char *ctr_name, uint32_t idx_cou stats += mod->stats_count; for (unsigned i = 0; i < threads; i++) { - uint64_t *new_vals = realloc(mod->stats_vals[i], - (offset + idx_count) * sizeof(*new_vals)); + knot_atomic_uint64_t *new_vals = realloc(mod->stats_vals[i], + (offset + idx_count) * sizeof(*new_vals)); if (new_vals == NULL) { knotd_mod_stats_free(mod); return KNOT_ENOMEM; @@ -627,6 +618,7 @@ uint32_t knotd_qdata_rtt(knotd_qdata_t *qdata) switch (qdata->params->proto) { case KNOTD_QUERY_PROTO_TCP: + case KNOTD_QUERY_PROTO_TLS: if (qdata->params->xdp_msg != NULL) { #ifdef ENABLE_XDP return qdata->params->measured_rtt; diff --git a/src/knot/nameserver/query_module.h b/src/knot/nameserver/query_module.h index 5cc905b..d403b25 100644 --- a/src/knot/nameserver/query_module.h +++ b/src/knot/nameserver/query_module.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -22,24 +22,27 @@ #include "knot/dnssec/zone-keys.h" #include "knot/include/module.h" #include "knot/server/server.h" +#include "contrib/atomic.h" #include "contrib/ucw/lists.h" -#ifdef HAVE_ATOMIC - #define ATOMIC_GET(src) __atomic_load_n(&(src), __ATOMIC_RELAXED) -#else - #define ATOMIC_GET(src) (src) -#endif +#define KNOTD_STAGES (KNOTD_STAGE_PROTO_END + 1) -#define KNOTD_STAGES (KNOTD_STAGE_END + 1) +typedef enum { + QUERY_HOOK_TYPE_PROTO, + QUERY_HOOK_TYPE_GENERAL, + QUERY_HOOK_TYPE_IN, +} query_hook_type_t; -typedef unsigned (*query_step_process_f) - (unsigned state, knot_pkt_t *pkt, knotd_qdata_t *qdata, knotd_mod_t *mod); - -/*! \brief Single processing step in query processing. */ +/*! \brief Single processing step in query/module processing. */ struct query_step { node_t node; + query_hook_type_t type; + union { + knotd_mod_proto_hook_f proto_hook; + knotd_mod_hook_f general_hook; + knotd_mod_in_hook_f in_hook; + }; void *ctx; - query_step_process_f process; }; /*! Query plan represents a sequence of steps needed for query processing @@ -58,7 +61,7 @@ void query_plan_free(struct query_plan *plan); /*! \brief Plan another step for given stage. */ int query_plan_step(struct query_plan *plan, knotd_stage_t stage, - query_step_process_f process, void *ctx); + query_hook_type_t type, void *hook, void *ctx); /*! \brief Open query module identified by name. */ knotd_mod_t *query_module_open(conf_t *conf, server_t *server, conf_mod_id_t *mod_id, @@ -91,7 +94,7 @@ struct knotd_mod { zone_keyset_t *keyset; zone_sign_ctx_t *sign_ctx; mod_ctr_t *stats_info; - uint64_t **stats_vals; + knot_atomic_uint64_t **stats_vals; uint32_t stats_count; void *ctx; }; diff --git a/src/knot/nameserver/update.c b/src/knot/nameserver/update.c index 1168c94..ee884fd 100644 --- a/src/knot/nameserver/update.c +++ b/src/knot/nameserver/update.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -22,12 +22,23 @@ #include "knot/query/requestor.h" #include "contrib/sockaddr.h" #include "libknot/libknot.h" +#include "libknot/quic/quic_conn.h" +#include "libknot/quic/tls.h" static int update_enqueue(zone_t *zone, knotd_qdata_t *qdata) { assert(zone); assert(qdata); + pthread_mutex_lock(&zone->ddns_lock); + if (zone->events.ufrozen && zone->ddns_queue_size >= 8) { + pthread_mutex_unlock(&zone->ddns_lock); + qdata->rcode = KNOT_RCODE_REFUSED; + qdata->rcode_ede = KNOT_EDNS_EDE_NOT_READY; + return KNOT_ELIMIT; + } + pthread_mutex_unlock(&zone->ddns_lock); + /* Create serialized request. */ knot_request_t *req = calloc(1, sizeof(*req)); if (req == NULL) { @@ -63,6 +74,22 @@ static int update_enqueue(zone_t *zone, knotd_qdata_t *qdata) assert(req->sign.tsig_key.algorithm == knot_tsig_rdata_alg(req->query->tsig_rr)); } +#ifdef ENABLE_QUIC + if (qdata->params->quic_conn != NULL) { + req->flags |= KNOT_REQUEST_QUIC; + req->quic_conn = qdata->params->quic_conn; + knot_quic_conn_block(req->quic_conn, true); + assert(qdata->params->quic_stream >= 0); + req->quic_stream = qdata->params->quic_stream; + } else +#endif // ENABLE_QUIC + if (qdata->params->tls_conn != NULL) { + req->flags |= KNOT_REQUEST_TLS; + req->tls_req_ctx.conn = qdata->params->tls_conn; + req->tls_req_ctx.conn->fd_clones_count++; + knot_tls_conn_block(req->tls_req_ctx.conn, true); + } + pthread_mutex_lock(&zone->ddns_lock); /* Enqueue created request. */ @@ -77,10 +104,10 @@ static int update_enqueue(zone_t *zone, knotd_qdata_t *qdata) return KNOT_EOK; } -int update_process_query(knot_pkt_t *pkt, knotd_qdata_t *qdata) +knot_layer_state_t update_process_query(knot_pkt_t *pkt, knotd_qdata_t *qdata) { /* DDNS over XDP not supported. */ - if (qdata->params->xdp_msg != NULL || qdata->params->proto == KNOTD_QUERY_PROTO_QUIC) { + if (qdata->params->xdp_msg != NULL) { qdata->rcode = KNOT_RCODE_SERVFAIL; return KNOT_STATE_FAIL; } @@ -95,8 +122,6 @@ int update_process_query(knot_pkt_t *pkt, knotd_qdata_t *qdata) NS_NEED_AUTH(qdata, ACL_ACTION_UPDATE); /* Check expiration. */ NS_NEED_ZONE_CONTENTS(qdata); - /* Check frozen zone. */ - NS_NEED_NOT_FROZEN(qdata); /* Store update into DDNS queue. */ int ret = update_enqueue((zone_t *)qdata->extra->zone, qdata); diff --git a/src/knot/nameserver/update.h b/src/knot/nameserver/update.h index 609acd9..430b323 100644 --- a/src/knot/nameserver/update.h +++ b/src/knot/nameserver/update.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -21,7 +21,5 @@ /*! * \brief UPDATE query processing module. - * - * \return KNOT_STATE_* processing states */ -int update_process_query(knot_pkt_t *pkt, knotd_qdata_t *qdata); +knot_layer_state_t update_process_query(knot_pkt_t *pkt, knotd_qdata_t *qdata); diff --git a/src/knot/nameserver/xfr.h b/src/knot/nameserver/xfr.h index e6d06b6..fe8a7a8 100644 --- a/src/knot/nameserver/xfr.h +++ b/src/knot/nameserver/xfr.h @@ -38,12 +38,12 @@ static inline void xfr_log_finished(const knot_dname_t *zone, log_operation_t op, log_direction_t dir, const struct sockaddr_storage *remote, knotd_query_proto_t proto, const knot_dname_t *key_name, - const struct xfr_stats *stats) + const char *serial_log, const struct xfr_stats *stats) { ns_log(LOG_INFO, zone, op, dir, remote, proto, false, key_name, - "%sfinished, %0.2f seconds, %u messages, %u bytes", + "%sfinished,%s %0.2f seconds, %u messages, %u bytes", (proto == KNOTD_QUERY_PROTO_QUIC && dir == LOG_DIRECTION_OUT ? "buffering " : ""), - time_diff_ms(&stats->begin, &stats->end) / 1000.0, + serial_log, time_diff_ms(&stats->begin, &stats->end) / 1000.0, stats->messages, stats->bytes); } diff --git a/src/knot/query/quic-requestor.c b/src/knot/query/quic-requestor.c index 62008f9..7492efd 100644 --- a/src/knot/query/quic-requestor.c +++ b/src/knot/query/quic-requestor.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -28,7 +28,6 @@ #include "knot/conf/conf.h" // please use this only for tiny stuff like quic-log #include "knot/server/handler.h" #include "libknot/error.h" -#include "libknot/quic/quic.h" #define QUIC_BUF_SIZE 4096 @@ -63,6 +62,7 @@ static int quic_exchange(knot_quic_conn_t *conn, knot_quic_reply_t *r, int timeo int64_t quic_timeout_ms = knot_quic_conn_next_timeout(conn); quic_timeout_ms = MIN(quic_timeout_ms, timeout_remain); quic_timeout_ms = MIN(quic_timeout_ms, timeout_ms / 2); + quic_timeout_ms = MAX(quic_timeout_ms, 1); r->in_payload->iov_len = QUIC_BUF_SIZE; @@ -156,7 +156,7 @@ int knot_qreq_connect(struct knot_quic_reply **out, int fd, struct sockaddr_storage *remote, struct sockaddr_storage *local, - const struct knot_quic_creds *local_creds, + const struct knot_creds *local_creds, const uint8_t *peer_pin, uint8_t peer_pin_len, bool *reused_fd, @@ -179,8 +179,7 @@ int knot_qreq_connect(struct knot_quic_reply **out, r->send_reply = qr_send_reply; r->free_reply = qr_free_reply; - struct knot_quic_creds *creds = knot_quic_init_creds_peer(local_creds, - peer_pin, peer_pin_len); + struct knot_creds *creds = knot_creds_init_peer(local_creds, peer_pin, peer_pin_len); if (creds == NULL) { free(r); return KNOT_ENOMEM; @@ -190,7 +189,7 @@ int knot_qreq_connect(struct knot_quic_reply **out, knot_quic_table_t *table = knot_quic_table_new(1, QUIC_BUF_SIZE, QUIC_BUF_SIZE, 0, creds); if (table == NULL) { - knot_quic_free_creds(creds); + knot_creds_free(creds); free(r); return KNOT_ENOMEM; } @@ -294,7 +293,7 @@ void knot_qreq_close(struct knot_quic_reply *r, bool send_close) knot_quic_table_rem(conn, table); knot_quic_cleanup(&conn, 1); if (table != NULL) { - knot_quic_free_creds(table->creds); + knot_creds_free(table->creds); } knot_quic_table_free(table); free(r); diff --git a/src/knot/query/quic-requestor.h b/src/knot/query/quic-requestor.h index b5f479e..083254d 100644 --- a/src/knot/query/quic-requestor.h +++ b/src/knot/query/quic-requestor.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -17,15 +17,13 @@ #pragma once #include "contrib/sockaddr.h" - -struct knot_quic_creds; -struct knot_quic_reply; +#include "libknot/quic/quic.h" int knot_qreq_connect(struct knot_quic_reply **out, int fd, struct sockaddr_storage *remote, struct sockaddr_storage *local, - const struct knot_quic_creds *local_creds, + const struct knot_creds *local_creds, const uint8_t *peer_pin, uint8_t peer_pin_len, bool *reused_fd, diff --git a/src/knot/query/requestor.c b/src/knot/query/requestor.c index 436f009..125c036 100644 --- a/src/knot/query/requestor.c +++ b/src/knot/query/requestor.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -18,12 +18,13 @@ #include <sys/socket.h> #include "libknot/attribute.h" +#include "libknot/errcode.h" +#include "libknot/quic/tls.h" #include "knot/common/unreachable.h" #include "knot/query/requestor.h" #ifdef ENABLE_QUIC #include "knot/query/quic-requestor.h" #endif // ENABLE_QUIC -#include "libknot/errcode.h" #include "contrib/conn_pool.h" #include "contrib/mempattern.h" #include "contrib/net.h" @@ -39,6 +40,11 @@ static bool use_quic(knot_request_t *request) return (request->flags & KNOT_REQUEST_QUIC) != 0; } +static bool use_tls(knot_request_t *request) +{ + return (request->flags & KNOT_REQUEST_TLS) != 0; +} + static bool is_answer_to_query(const knot_pkt_t *query, const knot_pkt_t *answer) { return knot_wire_get_id(query->wire) == knot_wire_get_id(answer->wire); @@ -104,6 +110,19 @@ static int request_ensure_connected(knot_request_t *request, bool *reused_fd, in #endif // ENABLE_QUIC } + if (use_tls(request)) { + assert(!use_quic(request)); + + int ret = knot_tls_req_ctx_init(&request->tls_req_ctx, request->fd, + request->creds, request->pin, + request->pin_len, timeout_ms); + if (ret != KNOT_EOK) { + close(request->fd); + request->fd = -1; + return ret; + } + } + return KNOT_EOK; } @@ -124,7 +143,9 @@ static int request_send(knot_request_t *request, int timeout_ms, bool *reused_fd &request->remote : NULL; /* Send query. */ - if (use_quic(request)) { + if (use_tls(request)) { + ret = knot_tls_send_dns(request->tls_req_ctx.conn, wire, wire_len); + } else if (use_quic(request)) { #ifdef ENABLE_QUIC struct iovec tosend = { wire, wire_len }; return knot_qreq_send(request->quic_ctx, &tosend); @@ -162,7 +183,9 @@ static int request_recv(knot_request_t *request, int timeout_ms) } /* Receive it */ - if (use_quic(request)) { + if (use_tls(request)) { + ret = knot_tls_recv_dns(request->tls_req_ctx.conn, resp->wire, resp->max_size); + } else if (use_quic(request)) { #ifdef ENABLE_QUIC struct iovec recvd = { resp->wire, resp->max_size }; ret = knot_qreq_recv(request->quic_ctx, &recvd, timeout_ms); @@ -192,7 +215,7 @@ knot_request_t *knot_request_make_generic(knot_mm_t *mm, const struct sockaddr_storage *remote, const struct sockaddr_storage *source, knot_pkt_t *query, - const struct knot_quic_creds *creds, + const struct knot_creds *creds, const query_edns_data_t *edns, const knot_tsig_key_t *tsig_key, const uint8_t *pin, @@ -232,7 +255,7 @@ knot_request_t *knot_request_make_generic(knot_mm_t *mm, request->edns = edns; request->creds = creds; - if (flags & KNOT_REQUEST_QUIC && pin_len > 0) { + if ((flags & (KNOT_REQUEST_QUIC | KNOT_REQUEST_TLS)) && pin_len > 0) { request->pin_len = pin_len; memcpy(request->pin, pin, pin_len); } @@ -243,12 +266,15 @@ knot_request_t *knot_request_make_generic(knot_mm_t *mm, knot_request_t *knot_request_make(knot_mm_t *mm, const conf_remote_t *remote, knot_pkt_t *query, - const struct knot_quic_creds *creds, + const struct knot_creds *creds, const query_edns_data_t *edns, knot_request_flag_t flags) { if (remote->quic) { + assert(!remote->tls); flags |= KNOT_REQUEST_QUIC; + } else if (remote->tls) { + flags |= KNOT_REQUEST_TLS; } return knot_request_make_generic(mm, &remote->addr, &remote->via, @@ -262,15 +288,25 @@ void knot_request_free(knot_request_t *request, knot_mm_t *mm) return; } - if (request->quic_ctx != NULL) { + if (use_quic(request)) { #ifdef ENABLE_QUIC - knot_qreq_close(request->quic_ctx, true); + if (request->quic_ctx != NULL) { + knot_qreq_close(request->quic_ctx, true); + } + // NOTE synthetic DDNSoQ request is NOOP here #else assert(0); #endif // ENABLE_QUIC + } else if (use_tls(request) && request->tls_req_ctx.conn != NULL) { + knot_tls_req_ctx_deinit(&request->tls_req_ctx); + } else { + assert(request->quic_ctx == NULL); + assert(request->quic_conn == NULL); + assert(request->tls_req_ctx.ctx == NULL); + assert(request->tls_req_ctx.conn == NULL); } - if (request->fd >= 0 && use_tcp(request) && + if (request->fd >= 0 && use_tcp(request) && !use_tls(request) && (request->flags & KNOT_REQUEST_KEEP)) { request->fd = (int)conn_pool_put(global_conn_pool, &request->source, @@ -282,6 +318,7 @@ void knot_request_free(knot_request_t *request, knot_mm_t *mm) } knot_pkt_free(request->query); knot_pkt_free(request->resp); + dnssec_binary_free(&request->sign.tsig_key.secret); tsig_cleanup(&request->tsig); mm_free(mm, request); @@ -351,7 +388,7 @@ static int request_produce(knot_requestor_t *req, knot_request_t *last, if (last->edns != NULL && !last->edns->no_edns) { ret = query_put_edns(last->query, last->edns, - (last->flags & KNOT_REQUEST_QUIC)); + (last->flags & (KNOT_REQUEST_QUIC | KNOT_REQUEST_TLS))); if (ret != KNOT_EOK) { return ret; } @@ -376,6 +413,9 @@ static int request_produce(knot_requestor_t *req, knot_request_t *last, if (last->flags & KNOT_REQUEST_QUIC) { req->layer.flags |= KNOT_REQUESTOR_QUIC; } + if (last->flags & KNOT_REQUEST_TLS) { + req->layer.flags |= KNOT_REQUESTOR_TLS; + } } return ret; diff --git a/src/knot/query/requestor.h b/src/knot/query/requestor.h index 65da1ed..241be04 100644 --- a/src/knot/query/requestor.h +++ b/src/knot/query/requestor.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -23,26 +23,26 @@ #include "knot/nameserver/tsig_ctx.h" #include "knot/query/layer.h" #include "knot/query/query.h" +#include "knot/query/tls-requestor.h" #include "libknot/mm_ctx.h" #include "libknot/rrtype/tsig.h" -struct knot_quic_creds; -struct knot_quic_reply; - typedef enum { KNOT_REQUEST_NONE = 0, /*!< Empty flag. */ KNOT_REQUEST_UDP = 1 << 0, /*!< Use UDP for requests. */ KNOT_REQUEST_TFO = 1 << 1, /*!< Enable TCP Fast Open for requests. */ KNOT_REQUEST_KEEP = 1 << 2, /*!< Keep upstream TCP connection in pool for later reuse. */ KNOT_REQUEST_QUIC = 1 << 3, /*!< Use QUIC/UDP for requests. */ - KNOT_REQUEST_FWD = 1 << 4, /*!< Forwarded message, don't modify (TSIG, PADDING). */ + KNOT_REQUEST_TLS = 1 << 4, /*!< Use DoT for requests. */ + KNOT_REQUEST_FWD = 1 << 5, /*!< Forwarded message, don't modify (TSIG, PADDING). */ } knot_request_flag_t; typedef enum { KNOT_REQUESTOR_CLOSE = 1 << 0, /*!< Close the connection indication. */ KNOT_REQUESTOR_REUSED = 1 << 1, /*!< Reused FD indication (RO). */ KNOT_REQUESTOR_QUIC = 1 << 2, /*!< QUIC used indication (RO). */ - KNOT_REQUESTOR_IOFAIL = 1 << 3, /*!< Encountered error sending/recving data. */ + KNOT_REQUESTOR_TLS = 1 << 3, /*!< DoT used indication (RO). */ + KNOT_REQUESTOR_IOFAIL = 1 << 4, /*!< Encountered error sending/recving data. */ } knot_requestor_flag_t; /*! \brief Requestor structure. @@ -57,7 +57,14 @@ typedef struct { /*! \brief Request data (socket, payload, response, TSIG and endpoints). */ typedef struct { int fd; - struct knot_quic_reply *quic_ctx; + union { + struct { + struct knot_quic_reply *quic_ctx; + struct knot_quic_conn *quic_conn; + int64_t quic_stream; + }; + knot_tls_req_ctx_t tls_req_ctx; + }; knot_request_flag_t flags; struct sockaddr_storage remote, source; knot_pkt_t *query; @@ -67,11 +74,22 @@ typedef struct { knot_sign_context_t sign; /*!< Required for async. DDNS processing. */ - const struct knot_quic_creds *creds; + const struct knot_creds *creds; size_t pin_len; uint8_t pin[]; } knot_request_t; +static inline knotd_query_proto_t flags2proto(unsigned layer_flags) +{ + knotd_query_proto_t proto = KNOTD_QUERY_PROTO_TCP; + if ((layer_flags & KNOT_REQUESTOR_QUIC)) { + proto = KNOTD_QUERY_PROTO_QUIC; + } else if ((layer_flags & KNOT_REQUESTOR_TLS)) { + proto = KNOTD_QUERY_PROTO_TLS; + } + return proto; +} + /*! * \brief Make request out of endpoints and query. * @@ -92,7 +110,7 @@ knot_request_t *knot_request_make_generic(knot_mm_t *mm, const struct sockaddr_storage *remote, const struct sockaddr_storage *source, knot_pkt_t *query, - const struct knot_quic_creds *creds, + const struct knot_creds *creds, const query_edns_data_t *edns, const knot_tsig_key_t *tsig_key, const uint8_t *pin, @@ -108,7 +126,7 @@ knot_request_t *knot_request_make_generic(knot_mm_t *mm, knot_request_t *knot_request_make(knot_mm_t *mm, const conf_remote_t *remote, knot_pkt_t *query, - const struct knot_quic_creds *creds, + const struct knot_creds *creds, const query_edns_data_t *edns, knot_request_flag_t flags); diff --git a/src/knot/query/tls-requestor.c b/src/knot/query/tls-requestor.c new file mode 100644 index 0000000..e1a2e8e --- /dev/null +++ b/src/knot/query/tls-requestor.c @@ -0,0 +1,59 @@ +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + 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 3 of the License, 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 <https://www.gnu.org/licenses/>. + */ + +#include <string.h> + +#include "knot/query/tls-requestor.h" +#include "libknot/error.h" +#include "libknot/quic/tls.h" + +int knot_tls_req_ctx_init(knot_tls_req_ctx_t *ctx, int fd, + const struct knot_creds *local_creds, + const uint8_t *peer_pin, uint8_t peer_pin_len, + int io_timeout_ms) +{ + struct knot_creds *creds = knot_creds_init_peer(local_creds, peer_pin, peer_pin_len); + if (creds == NULL) { + return KNOT_ENOMEM; + } + + // Use HS = 4x IO timeout, as the RMT IO timeout is usually high. + ctx->ctx = knot_tls_ctx_new(creds, io_timeout_ms, 4 * io_timeout_ms, false); + if (ctx->ctx == NULL) { + knot_creds_free(creds); + return KNOT_ENOMEM; + } + + ctx->conn = knot_tls_conn_new(ctx->ctx, fd); + if (ctx->conn == NULL) { + knot_tls_req_ctx_deinit(ctx); + return KNOT_ERROR; + } + + return KNOT_EOK; +} + +void knot_tls_req_ctx_deinit(knot_tls_req_ctx_t *ctx) +{ + if (ctx != NULL) { + if (ctx->ctx != NULL) { + knot_creds_free(ctx->ctx->creds); + } + knot_tls_conn_del(ctx->conn); + knot_tls_ctx_free(ctx->ctx); + memset(ctx, 0, sizeof(*ctx)); + } +} diff --git a/src/knot/query/tls-requestor.h b/src/knot/query/tls-requestor.h new file mode 100644 index 0000000..535bbe8 --- /dev/null +++ b/src/knot/query/tls-requestor.h @@ -0,0 +1,51 @@ +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + 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 3 of the License, 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 <https://www.gnu.org/licenses/>. + */ + +#pragma once + +#include <stdint.h> + +#include "libknot/quic/tls_common.h" + +/*! + * \brief TLS requestor context envelope, containing TLS general context and TLS connection. + */ +typedef struct knot_tls_req_ctx { + struct knot_tls_ctx *ctx; + struct knot_tls_conn *conn; +} knot_tls_req_ctx_t; + +/*! + * \brief Initialize TLS requestor context. + * + * \param ctx Context structure to be initialized. + * \param fd Opened TCP connection file descriptor. + * \param local_creds Local TLS credentials. + * \param peer_pin TLS peer pin. + * \param peer_pin_len TLS peer pin length. + * \param io_timeout_ms Configured io-timeout for TLS connection. + * + * \return KNOT_E* + */ +int knot_tls_req_ctx_init(knot_tls_req_ctx_t *ctx, int fd, + const struct knot_creds *local_creds, + const uint8_t *peer_pin, uint8_t peer_pin_len, + int io_timeout_ms); + +/*! + * \brief De-initialize TLS requestor context. + */ +void knot_tls_req_ctx_deinit(knot_tls_req_ctx_t *ctx); diff --git a/src/knot/server/handler.c b/src/knot/server/handler.c index ec7377a..bcd0ec5 100644 --- a/src/knot/server/handler.c +++ b/src/knot/server/handler.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -97,7 +97,7 @@ static void handle_quic_stream(knot_quic_conn_t *conn, int64_t stream_id, struct } void handle_quic_streams(knot_quic_conn_t *conn, knotd_qdata_params_t *params, - knot_layer_t *layer, void *msg) + knot_layer_t *layer) { uint8_t ans_buf[KNOT_WIRE_MAX_PKTSIZE]; @@ -108,14 +108,7 @@ void handle_quic_streams(knot_quic_conn_t *conn, knotd_qdata_params_t *params, assert(stream->inbufs != NULL); assert(stream->inbufs->n_inbufs > 0); struct iovec *inbufs = stream->inbufs->inbufs; - if (msg) { -#ifdef ENABLE_XDP - params_xdp_update(params, KNOTD_QUERY_PROTO_QUIC, msg, - knot_quic_conn_rtt(conn), conn); -#endif // ENABLE_XDP - } else { - params_update(params, knot_quic_conn_rtt(conn), conn); - } + params_update_quic(params, knot_quic_conn_rtt(conn), conn, stream_id); // NOTE: only the first msg in the stream is used, the rest is dropped. handle_quic_stream(conn, stream_id, &inbufs[0], layer, params, ans_buf, sizeof(ans_buf)); diff --git a/src/knot/server/handler.h b/src/knot/server/handler.h index 0f29988..4b63a0c 100644 --- a/src/knot/server/handler.h +++ b/src/knot/server/handler.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -20,6 +20,7 @@ #include "knot/query/layer.h" #include "knot/server/server.h" #include "libknot/xdp/tcp_iobuf.h" +#include "libknot/quic/tls.h" #ifdef ENABLE_QUIC #include "libknot/quic/quic.h" @@ -44,18 +45,33 @@ inline static knotd_qdata_params_t params_init(knotd_query_proto_t proto, .remote = (const struct sockaddr_storage *)remote, .local = (const struct sockaddr_storage *)local, .socket = sock, + .thread_id = thread_id, .server = server, - .thread_id = thread_id + .quic_stream = -1, }; return params; } -inline static void params_update(knotd_qdata_params_t *params, uint32_t rtt, - struct knot_quic_conn *conn) +inline static void params_update_tcp(knotd_qdata_params_t *params, uint32_t rtt) { params->measured_rtt = rtt; +} + +#ifdef ENABLE_QUIC +inline static void params_update_quic(knotd_qdata_params_t *params, uint32_t rtt, + knot_quic_conn_t *conn, int64_t stream_id) +{ params->quic_conn = conn; + params->quic_stream = stream_id; + params->measured_rtt = rtt; +} +#endif // ENABLE_QUIC + +inline static void params_update_tls(knotd_qdata_params_t *params, + knot_tls_conn_t *conn) +{ + params->tls_conn = conn; } #ifdef ENABLE_XDP @@ -64,8 +80,9 @@ inline static knotd_qdata_params_t params_xdp_init(int sock, server_t *server, { knotd_qdata_params_t params = { .socket = sock, + .thread_id = thread_id, .server = server, - .thread_id = thread_id + .quic_stream = -1, }; return params; @@ -73,16 +90,12 @@ inline static knotd_qdata_params_t params_xdp_init(int sock, server_t *server, inline static void params_xdp_update(knotd_qdata_params_t *params, knotd_query_proto_t proto, - struct knot_xdp_msg *msg, - uint32_t rtt, - struct knot_quic_conn *conn) + struct knot_xdp_msg *msg) { params->proto = proto; params->remote = (struct sockaddr_storage *)&msg->ip_from; params->local = (struct sockaddr_storage *)&msg->ip_to; params->xdp_msg = msg; - params->measured_rtt = rtt; - params->quic_conn = conn; } #endif // ENABLE_XDP @@ -107,7 +120,7 @@ void handle_udp_reply(knotd_qdata_params_t *params, knot_layer_t *layer, #ifdef ENABLE_QUIC void handle_quic_streams(knot_quic_conn_t *conn, knotd_qdata_params_t *params, - knot_layer_t *layer, void *msg); + knot_layer_t *layer); #endif // ENABLE_QUIC void log_swept(knot_sweep_stats_t *stats, bool tcp); diff --git a/src/knot/server/quic-handler.c b/src/knot/server/quic-handler.c index 5010213..663167e 100644 --- a/src/knot/server/quic-handler.c +++ b/src/knot/server/quic-handler.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -24,6 +24,7 @@ #include "contrib/macros.h" #include "contrib/net.h" #include "knot/common/log.h" +#include "knot/nameserver/process_query.h" #include "knot/server/handler.h" #include "knot/server/quic-handler.h" #include "knot/server/server.h" @@ -92,16 +93,22 @@ void quic_handler(knotd_qdata_params_t *params, knot_layer_t *layer, rpl.out_payload->iov_len = 0; // prevent send attempt if uq_alloc_reply is not called at all + if (process_query_proto(params, KNOTD_STAGE_PROTO_BEGIN) == KNOTD_PROTO_STATE_BLOCK) { + return; + } + knot_quic_conn_t *conn = NULL; (void)knot_quic_handle(table, &rpl, idle_close, &conn); if (conn != NULL) { - handle_quic_streams(conn, params, layer, NULL); + handle_quic_streams(conn, params, layer); (void)knot_quic_send(table, conn, &rpl, QUIC_MAX_SEND_PER_RECV, 0); knot_quic_cleanup(&conn, 1); } + + (void)process_query_proto(params, KNOTD_STAGE_PROTO_END); } knot_quic_table_t *quic_make_table(struct server *server) diff --git a/src/knot/server/server.c b/src/knot/server/server.c index dd0b025..0626337 100644 --- a/src/knot/server/server.c +++ b/src/knot/server/server.c @@ -27,8 +27,9 @@ #include "libknot/libknot.h" #include "libknot/yparser/ypschema.h" #include "libknot/xdp.h" +#include "libknot/quic/tls_common.h" #ifdef ENABLE_QUIC -#include "libknot/quic/quic.h" +#include "libknot/quic/quic.h" // knot_quic_session_* #endif // ENABLE_QUIC #include "knot/common/log.h" #include "knot/common/stats.h" @@ -65,6 +66,8 @@ #define SESSION_TICKET_POOL_TIMEOUT (24 * 3600) +#define QUIC_LOG "QUIC/TLS, " + /*! \brief Minimal send/receive buffer sizes. */ enum { UDP_MIN_RCVSIZE = 4096, @@ -236,14 +239,14 @@ static int disable_pmtudisc(int sock, int family) return KNOT_EOK; } -static size_t quic_rmt_count(conf_t *conf) +static size_t quic_rmt_count(conf_t *conf, const yp_name_t *proto) { size_t count = 0; for (conf_iter_t iter = conf_iter(conf, C_RMT); iter.code == KNOT_EOK; conf_iter_next(conf, &iter)) { conf_val_t id = conf_iter_id(conf, &iter); - conf_val_t rmt_quic = conf_id_get(conf, C_RMT, C_QUIC, &id); + conf_val_t rmt_quic = conf_id_get(conf, C_RMT, proto, &id); if (conf_bool(&rmt_quic)) { count++; } @@ -252,14 +255,11 @@ static size_t quic_rmt_count(conf_t *conf) return count; } +#ifdef ENABLE_XDP static iface_t *server_init_xdp_iface(struct sockaddr_storage *addr, bool route_check, bool udp, bool tcp, uint16_t quic, unsigned *thread_id_start, - bool extra_frames) + const knot_xdp_config_t *xdp_config) { -#ifndef ENABLE_XDP - assert(0); - return NULL; -#else conf_xdp_iface_t iface; int ret = conf_xdp_iface(addr, &iface); if (ret != KNOT_EOK) { @@ -296,18 +296,17 @@ static iface_t *server_init_xdp_iface(struct sockaddr_storage *addr, bool route_ xdp_flags |= KNOT_XDP_FILTER_ROUTE; } - knot_xdp_config_t xdp_config = { .extra_frames = extra_frames }; for (int i = 0; i < iface.queues; i++) { knot_xdp_load_bpf_t mode = (i == 0 ? KNOT_XDP_LOAD_BPF_ALWAYS : KNOT_XDP_LOAD_BPF_NEVER); ret = knot_xdp_init(new_if->xdp_sockets + i, iface.name, i, - xdp_flags, iface.port, quic, mode, &xdp_config); + xdp_flags, iface.port, quic, mode, xdp_config); if (ret == -EBUSY && i == 0) { log_notice("XDP interface %s@%u is busy, retrying initialization", iface.name, iface.port); ret = knot_xdp_init(new_if->xdp_sockets + i, iface.name, i, xdp_flags, iface.port, quic, - KNOT_XDP_LOAD_BPF_ALWAYS_UNLOAD, &xdp_config); + KNOT_XDP_LOAD_BPF_ALWAYS_UNLOAD, xdp_config); } if (ret != KNOT_EOK) { log_warning("failed to initialize XDP interface %s@%u, queue %d (%s)", @@ -345,8 +344,8 @@ static iface_t *server_init_xdp_iface(struct sockaddr_storage *addr, bool route_ } return new_if; -#endif } +#endif /*! * \brief Create and initialize new interface. @@ -363,7 +362,7 @@ static iface_t *server_init_xdp_iface(struct sockaddr_storage *addr, bool route_ * \retval Pointer to a new initialized interface. * \retval NULL if error. */ -static iface_t *server_init_iface(struct sockaddr_storage *addr, bool quic, +static iface_t *server_init_iface(struct sockaddr_storage *addr, bool tls, int udp_thread_count, int tcp_thread_count, bool tcp_reuseport, bool socket_affinity) { @@ -380,14 +379,14 @@ static iface_t *server_init_iface(struct sockaddr_storage *addr, bool quic, int udp_socket_count = 1; int udp_bind_flags = 0; - int tcp_socket_count = !quic ? 1 : 0; + int tcp_socket_count = tcp_thread_count > 0 ? 1 : 0; int tcp_bind_flags = 0; #ifdef ENABLE_REUSEPORT udp_socket_count = udp_thread_count; udp_bind_flags |= NET_BIND_MULTIPLE; - if (!quic && tcp_reuseport) { + if (tcp_reuseport) { tcp_socket_count = tcp_thread_count; tcp_bind_flags |= NET_BIND_MULTIPLE; } @@ -459,7 +458,7 @@ static iface_t *server_init_iface(struct sockaddr_storage *addr, bool quic, warn_flag_misc = false; } - if (quic) { + if (tls) { ret = net_cmsg_ecn_enable(sock, addr->ss_family); if (ret != KNOT_EOK && ret != KNOT_ENOTSUP && warn_ecn) { log_warning("failed to enable ECN for QUIC"); @@ -561,7 +560,6 @@ static void log_sock_conf(conf_t *conf) } } -#ifdef ENABLE_QUIC static int check_file(char *path, char *role) { if (path == NULL) { @@ -576,29 +574,29 @@ static int check_file(char *path, char *role) err_str = "invalid file"; } else if (!S_ISREG(st.st_mode)) { err_str = "not a file"; + } else if ((st.st_mode & S_IRUSR) == 0) { + err_str = "not readable"; } else { return KNOT_EOK; } - log_error("QUIC, %s file '%s' (%s)", role, path, err_str); + log_error(QUIC_LOG "%s file '%s' (%s)", role, path, err_str); return KNOT_EINVAL; } -#endif // ENABLE_QUIC -static int init_creds(server_t *server, conf_t *conf) +static int init_creds(conf_t *conf, server_t *server) { -#ifdef ENABLE_QUIC char *cert_file = conf_tls(conf, C_CERT_FILE); char *key_file = conf_tls(conf, C_KEY_FILE); int ret = check_file(cert_file, "certificate"); if (ret != KNOT_EOK) { - return ret; + goto failed; } ret = check_file(key_file, "key"); if (ret != KNOT_EOK) { - return ret; + goto failed; } if (cert_file == NULL) { @@ -606,35 +604,45 @@ static int init_creds(server_t *server, conf_t *conf) char *kasp_dir = conf_db(conf, C_KASP_DB); ret = make_dir(kasp_dir, S_IRWXU | S_IRWXG, true); if (ret != KNOT_EOK) { - log_error("QUIC, failed to create directory '%s'", kasp_dir); + log_error(QUIC_LOG "failed to create directory '%s'", kasp_dir); free(kasp_dir); - return ret; + goto failed; } key_file = abs_path(DFLT_QUIC_KEY_FILE, kasp_dir); free(kasp_dir); - log_debug("QUIC, using self-generated key '%s' with " + log_debug(QUIC_LOG "using self-generated key '%s' with " "one-time certificate", key_file); } - server->quic_creds = knot_quic_init_creds(cert_file, key_file); - free(cert_file); + + uint8_t prev_pin[128]; + size_t prev_pin_len = server_cert_pin(server, prev_pin, sizeof(prev_pin)); + if (server->quic_creds == NULL) { - log_error("QUIC, failed to initialize server credentials with key '%s'", - key_file); - free(key_file); - return KNOT_ERROR; + server->quic_creds = knot_creds_init(key_file, cert_file); + if (server->quic_creds == NULL) { + log_error(QUIC_LOG "failed to initialize server credentials"); + ret = KNOT_ERROR; + goto failed; + } + } else { + ret = knot_creds_update(server->quic_creds, key_file, cert_file); + if (ret != KNOT_EOK) { + goto failed; + } } - free(key_file); - size_t pin_len; uint8_t pin[128]; - if ((pin_len = server_cert_pin(server, pin, sizeof(pin))) > 0) { - log_info("QUIC, certificate public key %.*s", (int)pin_len, pin); + size_t pin_len = server_cert_pin(server, pin, sizeof(pin)); + if (pin_len > 0 && (pin_len != prev_pin_len || memcmp(pin, prev_pin, pin_len) != 0)) { + log_info(QUIC_LOG "certificate public key %.*s", (int)pin_len, pin); } - return KNOT_EOK; -#else - return KNOT_ERROR; -#endif // ENABLE_QUIC + ret = KNOT_EOK; +failed: + free(key_file); + free(cert_file); + + return ret; } /*! \brief Initialize bound sockets according to configuration. */ @@ -646,11 +654,13 @@ static int configure_sockets(conf_t *conf, server_t *s) conf_val_t listen_val = conf_get(conf, C_SRV, C_LISTEN); conf_val_t liquic_val = conf_get(conf, C_SRV, C_LISTEN_QUIC); + conf_val_t listls_val = conf_get(conf, C_SRV, C_LISTEN_TLS); conf_val_t lisxdp_val = conf_get(conf, C_XDP, C_LISTEN); conf_val_t rundir_val = conf_get(conf, C_SRV, C_RUNDIR); uint16_t convent_quic = conf_val_count(&liquic_val); + uint16_t convent_tls = conf_val_count(&listls_val); - if (listen_val.code == KNOT_EOK || liquic_val.code == KNOT_EOK) { + if (listen_val.code == KNOT_EOK || liquic_val.code == KNOT_EOK || listls_val.code == KNOT_EOK) { log_sock_conf(conf); } else if (lisxdp_val.code != KNOT_EOK) { log_warning("no network interface configured"); @@ -676,7 +686,7 @@ static int configure_sockets(conf_t *conf, server_t *s) size_t real_nifs = 0; size_t nifs = conf_val_count(&listen_val) + conf_val_count(&liquic_val) + - conf_val_count(&lisxdp_val); + conf_val_count(&listls_val) + conf_val_count(&lisxdp_val); iface_t *newlist = calloc(nifs, sizeof(*newlist)); if (newlist == NULL) { log_error("failed to allocate memory for network sockets"); @@ -720,32 +730,52 @@ static int configure_sockets(conf_t *conf, server_t *s) free(rundir); return KNOT_ERROR; } - new_if->quic = true; + new_if->tls = true; memcpy(&newlist[real_nifs++], new_if, sizeof(*newlist)); free(new_if); conf_val_next(&liquic_val); } + while (listls_val.code == KNOT_EOK) { + struct sockaddr_storage addr = conf_addr(&listls_val, rundir); + char addr_str[SOCKADDR_STRLEN] = { 0 }; + sockaddr_tostr(addr_str, sizeof(addr_str), &addr); + log_info("binding to TLS interface %s", addr_str); + + iface_t *new_if = server_init_iface(&addr, true, 0, size_tcp, + tcp_reuseport, socket_affinity); + if (new_if == NULL) { + server_deinit_iface_list(newlist, nifs); + free(rundir); + return KNOT_ERROR; + } + new_if->tls = true; + memcpy(&newlist[real_nifs++], new_if, sizeof(*newlist)); + free(new_if); + + conf_val_next(&listls_val); + } free(rundir); /* XDP sockets. */ - bool xdp_udp = conf->cache.xdp_udp; - bool xdp_tcp = conf->cache.xdp_tcp; - uint16_t xdp_quic = conf->cache.xdp_quic; - bool route_check = conf->cache.xdp_route_check; +#ifdef ENABLE_XDP + knot_xdp_config_t xdp_config = { + .ring_size = conf->cache.xdp_ring_size, + .busy_poll_budget = conf->cache.xdp_busypoll_budget, + .busy_poll_timeout = conf->cache.xdp_busypoll_timeout, + }; unsigned thread_id = s->handlers[IO_UDP].handler.unit->size + s->handlers[IO_TCP].handler.unit->size; - conf_val_t extra_frames_val = conf_get(conf, C_XDP, C_EXTRA_FRAMES); - bool extra_frames = conf_bool(&extra_frames_val); while (lisxdp_val.code == KNOT_EOK) { struct sockaddr_storage addr = conf_addr(&lisxdp_val, NULL); char addr_str[SOCKADDR_STRLEN] = { 0 }; sockaddr_tostr(addr_str, sizeof(addr_str), &addr); log_info("binding to XDP interface %s", addr_str); - iface_t *new_if = server_init_xdp_iface(&addr, route_check, xdp_udp, - xdp_tcp, xdp_quic, &thread_id, - extra_frames); + iface_t *new_if = server_init_xdp_iface(&addr, conf->cache.xdp_route_check, + conf->cache.xdp_udp, conf->cache.xdp_tcp, + conf->cache.xdp_quic, &thread_id, + &xdp_config); if (new_if == NULL) { server_deinit_iface_list(newlist, nifs); return KNOT_ERROR; @@ -755,13 +785,16 @@ static int configure_sockets(conf_t *conf, server_t *s) conf_val_next(&lisxdp_val); } +#endif + assert(real_nifs <= nifs); nifs = real_nifs; /* QUIC credentials initialization. */ - s->quic_active = xdp_quic > 0 || convent_quic > 0 || quic_rmt_count(conf) > 0; - if (s->quic_active) { - if (init_creds(s, conf) != KNOT_EOK) { + s->quic_active = conf->cache.xdp_quic > 0 || convent_quic > 0 || quic_rmt_count(conf, C_QUIC) > 0; + s->tls_active = convent_tls > 0 || quic_rmt_count(conf, C_TLS) > 0; + if (s->quic_active || s->tls_active) { + if (init_creds(conf, s) != KNOT_EOK) { server_deinit_iface_list(newlist, nifs); return KNOT_ERROR; } @@ -810,6 +843,8 @@ int server_init(server_t *server, int bg_workers) return ret; } + pthread_rwlock_init(&server->ctl_lock, NULL); + zone_backups_init(&server->backup_ctxs); char *catalog_dir = conf_db(conf(), C_CATALOG_DB); @@ -864,6 +899,9 @@ void server_deinit(server_t *server) /* Free remaining events. */ evsched_deinit(&server->sched); + /* Deinit locks. */ + pthread_rwlock_destroy(&server->ctl_lock); + /* Free catalog zone context. */ catalog_update_clear(&server->catalog_upd); catalog_update_deinit(&server->catalog_upd); @@ -885,9 +923,7 @@ void server_deinit(server_t *server) global_sessticket_pool = NULL; knot_unreachables_deinit(&global_unreachables); -#if defined ENABLE_QUIC - knot_quic_free_creds(server->quic_creds); -#endif // ENABLE_QUIC + knot_creds_free(server->quic_creds); } static int server_init_handler(server_t *server, int index, int thread_count, @@ -1058,9 +1094,10 @@ static bool listen_changed(conf_t *conf, server_t *server) conf_val_t listen_val = conf_get(conf, C_SRV, C_LISTEN); conf_val_t liquic_val = conf_get(conf, C_SRV, C_LISTEN_QUIC); + conf_val_t listls_val = conf_get(conf, C_SRV, C_LISTEN_TLS); conf_val_t lisxdp_val = conf_get(conf, C_XDP, C_LISTEN); size_t new_count = conf_val_count(&listen_val) + conf_val_count(&liquic_val) + - conf_val_count(&lisxdp_val); + conf_val_count(&listls_val) + conf_val_count(&lisxdp_val); size_t old_count = server->n_ifaces; if (new_count != old_count) { return true; @@ -1075,7 +1112,9 @@ static bool listen_changed(conf_t *conf, server_t *server) struct sockaddr_storage addr = conf_addr(&listen_val, rundir); bool found = false; for (size_t i = 0; i < server->n_ifaces; i++) { - if (sockaddr_cmp(&addr, &server->ifaces[i].addr, false) == 0) { + iface_t *iface = &server->ifaces[i]; + if (sockaddr_cmp(&addr, &iface->addr, false) == 0 && + !iface->tls && iface->fd_xdp_count == 0) { matches++; found = true; break; @@ -1090,7 +1129,9 @@ static bool listen_changed(conf_t *conf, server_t *server) struct sockaddr_storage addr = conf_addr(&liquic_val, rundir); bool found = false; for (size_t i = 0; i < server->n_ifaces; i++) { - if (sockaddr_cmp(&addr, &server->ifaces[i].addr, false) == 0) { + iface_t *iface = &server->ifaces[i]; + if (sockaddr_cmp(&addr, &iface->addr, false) == 0 && + iface->tls && iface->fd_udp_count > 0) { matches++; found = true; break; @@ -1101,13 +1142,32 @@ static bool listen_changed(conf_t *conf, server_t *server) } conf_val_next(&liquic_val); } + while (listls_val.code == KNOT_EOK) { + struct sockaddr_storage addr = conf_addr(&listls_val, rundir); + bool found = false; + for (size_t i = 0; i < server->n_ifaces; i++) { + iface_t *iface = &server->ifaces[i]; + if (sockaddr_cmp(&addr, &iface->addr, false) == 0 && + iface->tls && iface->fd_tcp_count > 0) { + matches++; + found = true; + break; + } + } + if (!found) { + break; + } + conf_val_next(&listls_val); + } free(rundir); while (lisxdp_val.code == KNOT_EOK) { struct sockaddr_storage addr = conf_addr(&lisxdp_val, NULL); bool found = false; for (size_t i = 0; i < server->n_ifaces; i++) { - if (sockaddr_cmp(&addr, &server->ifaces[i].addr, false) == 0) { + iface_t *iface = &server->ifaces[i]; + if (sockaddr_cmp(&addr, &iface->addr, false) == 0 && + iface->fd_xdp_count > 0) { matches++; found = true; break; @@ -1137,6 +1197,9 @@ static void warn_server_reconfigure(conf_t *conf, server_t *server) static bool warn_xdp_tcp = true; static bool warn_xdp_quic = true; static bool warn_route_check = true; + static bool warn_ring_size = true; + static bool warn_busypoll_budget = true; + static bool warn_busypoll_timeout = true; static bool warn_rmt_pool_limit = true; if (warn_tcp_reuseport && conf->cache.srv_tcp_reuseport != conf_get_bool(conf, C_SRV, C_TCP_REUSEPORT)) { @@ -1165,7 +1228,7 @@ static void warn_server_reconfigure(conf_t *conf, server_t *server) } if (warn_listen && server->ifaces != NULL && listen_changed(conf, server)) { - log_warning(msg, "listen(-xdp,-quic)"); + log_warning(msg, "listen(-xdp,-quic,-tls)"); warn_listen = false; } @@ -1195,6 +1258,21 @@ static void warn_server_reconfigure(conf_t *conf, server_t *server) warn_route_check = false; } + if (warn_ring_size && conf->cache.xdp_ring_size != conf_get_int(conf, C_XDP, C_RING_SIZE)) { + log_warning(msg, &C_RING_SIZE[1]); + warn_ring_size = false; + } + + if (warn_busypoll_budget && conf->cache.xdp_busypoll_budget != conf_get_int(conf, C_XDP, C_BUSYPOLL_BUDGET)) { + log_warning(msg, &C_BUSYPOLL_BUDGET[1]); + warn_busypoll_budget = false; + } + + if (warn_busypoll_timeout && conf->cache.xdp_busypoll_timeout != conf_get_int(conf, C_XDP, C_BUSYPOLL_TIMEOUT)) { + log_warning(msg, &C_BUSYPOLL_TIMEOUT[1]); + warn_busypoll_timeout = false; + } + if (warn_rmt_pool_limit && global_conn_pool != NULL && global_conn_pool->capacity != conf_get_int(conf, C_SRV, C_RMT_POOL_LIMIT)) { log_warning(msg, &C_RMT_POOL_LIMIT[1]); @@ -1395,7 +1473,7 @@ static int reconfigure_remote_pool(conf_t *conf, server_t *server) #ifdef ENABLE_QUIC if (global_sessticket_pool == NULL && server->quic_active) { - size_t rmt_count = quic_rmt_count(conf); + size_t rmt_count = quic_rmt_count(conf, C_QUIC); if (rmt_count > 0) { size_t max_tickets = conf_bg_threads(conf) * rmt_count * 2; // Two addresses per remote. conn_pool_t *new_pool = @@ -1456,6 +1534,12 @@ int server_reconfigure(conf_t *conf, server_t *server) if (conf_lmdb_readers(conf) > CONF_MAX_DB_READERS) { log_warning("config, exceeded number of database readers"); } + } else { + /* Reconfigure TLS credentials. */ + if ((ret = init_creds(conf, server)) != KNOT_EOK) { + log_error("failed to reconfigure server credentials (%s)", + knot_strerror(ret)); + } } /* Reconfigure journal DB. */ @@ -1515,14 +1599,13 @@ void server_update_zones(conf_t *conf, server_t *server, reload_t mode) size_t server_cert_pin(server_t *server, uint8_t *out, size_t out_size) { -#ifdef ENABLE_QUIC int pin_size = 0; - uint8_t bin_pin[KNOT_QUIC_PIN_LEN]; + uint8_t bin_pin[KNOT_TLS_PIN_LEN]; size_t bin_pin_size = sizeof(bin_pin); gnutls_x509_crt_t cert = NULL; if (server->quic_creds != NULL && - knot_quic_creds_cert(server->quic_creds, &cert) == KNOT_EOK && + knot_creds_cert(server->quic_creds, &cert) == KNOT_EOK && gnutls_x509_crt_get_key_id(cert, GNUTLS_KEYID_USE_SHA256, bin_pin, &bin_pin_size) == GNUTLS_E_SUCCESS) { pin_size = knot_base64_encode(bin_pin, bin_pin_size, out, out_size); @@ -1530,7 +1613,4 @@ size_t server_cert_pin(server_t *server, uint8_t *out, size_t out_size) gnutls_x509_crt_deinit(cert); return (pin_size >= 0) ? pin_size : 0; -#else - return 0; -#endif // ENABLE_QUIC } diff --git a/src/knot/server/server.h b/src/knot/server/server.h index e72e6de..fae06d6 100644 --- a/src/knot/server/server.h +++ b/src/knot/server/server.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -16,8 +16,7 @@ #pragma once -#include <stdatomic.h> - +#include "contrib/atomic.h" #include "knot/conf/conf.h" #include "knot/catalog/catalog_update.h" #include "knot/common/evsched.h" @@ -32,7 +31,7 @@ struct server; struct knot_xdp_socket; -struct knot_quic_creds; +struct knot_creds; /*! * \brief I/O handler structure. @@ -75,7 +74,7 @@ typedef struct { unsigned fd_xdp_count; unsigned xdp_first_thread_id; bool anyaddr; - bool quic; + bool tls; struct knot_xdp_socket **xdp_sockets; struct sockaddr_storage addr; } iface_t; @@ -120,16 +119,20 @@ typedef struct server { iface_t *ifaces; size_t n_ifaces; bool quic_active; + bool tls_active; + + /*! \brief Mutex protecting simultaneous access from concurrent CTL threads. */ + pthread_rwlock_t ctl_lock; /*! \brief Pending changes to catalog member zones, update indication. */ catalog_update_t catalog_upd; - atomic_bool catalog_upd_signal; + knot_atomic_bool catalog_upd_signal; /*! \brief Context of pending zones' backup. */ zone_backup_ctxs_t backup_ctxs; /*! \brief Crendentials context for QUIC. */ - struct knot_quic_creds *quic_creds; + struct knot_creds *quic_creds; } server_t; /*! diff --git a/src/knot/server/tcp-handler.c b/src/knot/server/tcp-handler.c index 305b2f4..7af2f58 100644 --- a/src/knot/server/tcp-handler.c +++ b/src/knot/server/tcp-handler.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -36,6 +36,7 @@ #include "knot/common/fdset.h" #include "knot/nameserver/process_query.h" #include "knot/query/layer.h" +#include "libknot/quic/tls.h" #include "contrib/macros.h" #include "contrib/mempattern.h" #include "contrib/net.h" @@ -57,6 +58,7 @@ typedef struct tcp_context { unsigned max_worker_fds; /*!< Max TCP clients per worker configuration + no. of ifaces. */ int idle_timeout; /*!< [s] TCP idle timeout configuration. */ int io_timeout; /*!< [ms] TCP send/recv timeout configuration. */ + struct knot_tls_ctx *tls_ctx; /*!< DoT answering context. */ } tcp_context_t; #define TCP_SWEEP_INTERVAL 2 /*!< [secs] granularity of connection sweeping. */ @@ -76,11 +78,22 @@ static void update_tcp_conf(tcp_context_t *tcp) tcp->idle_timeout = pconf->cache.srv_tcp_idle_timeout; tcp->io_timeout = pconf->cache.srv_tcp_io_timeout; rcu_read_unlock(); + + if (tcp->tls_ctx != NULL) { + tcp->tls_ctx->io_timeout = tcp->io_timeout; + } +} + +static void free_tls_ctx(fdset_t *set, int idx) +{ + void *tls_conn = *fdset_ctx2(set, idx); + knot_tls_conn_del(tls_conn); } /*! \brief Sweep TCP connection. */ -static fdset_sweep_state_t tcp_sweep(fdset_t *set, int fd, _unused_ void *data) +static fdset_sweep_state_t tcp_sweep(fdset_t *set, int idx, _unused_ void *data) { + const int fd = fdset_get_fd(set, idx); assert(set && fd >= 0); /* Best-effort, name and shame. */ @@ -92,6 +105,8 @@ static fdset_sweep_state_t tcp_sweep(fdset_t *set, int fd, _unused_ void *data) log_notice("TCP, terminated inactive client, address %s", addr_str); } + free_tls_ctx(set, idx); + return FDSET_SWEEP; } @@ -107,15 +122,14 @@ static void tcp_log_error(const struct sockaddr_storage *ss, const char *operati } static unsigned tcp_set_ifaces(const iface_t *ifaces, size_t n_ifaces, - fdset_t *fds, int thread_id) + fdset_t *fds, int thread_id, bool *tls) { if (n_ifaces == 0) { return 0; } for (const iface_t *i = ifaces; i != ifaces + n_ifaces; i++) { - if (i->fd_tcp_count == 0 || i->quic) { // Ignore XDP and QUIC interfaces. - assert(i->fd_xdp_count > 0 || i->quic); + if (i->fd_xdp_count > 0 || i->fd_tcp_count == 0) { // Ignore XDP and QUIC interfaces. continue; } @@ -133,31 +147,44 @@ static unsigned tcp_set_ifaces(const iface_t *ifaces, size_t n_ifaces, if (ret < 0) { return 0; } + if (i->tls) { + *tls = true; + } } return fdset_get_length(fds); } -static int tcp_handle(tcp_context_t *tcp, int fd, const sockaddr_t *remote, - const sockaddr_t *local, struct iovec *rx, struct iovec *tx) +static int tcp_handle(tcp_context_t *tcp, knotd_qdata_params_t *params, + struct iovec *rx, struct iovec *tx) { - /* Create query processing parameter. */ - knotd_qdata_params_t params = params_init(KNOTD_QUERY_PROTO_TCP, remote, local, - fd, tcp->server, tcp->thread_id); - rx->iov_len = KNOT_WIRE_MAX_PKTSIZE; tx->iov_len = KNOT_WIRE_MAX_PKTSIZE; /* Receive data. */ - int recv = net_dns_tcp_recv(fd, rx->iov_base, rx->iov_len, tcp->io_timeout); + int recv; + if (params->tls_conn != NULL) { + int ret = knot_tls_handshake(params->tls_conn, true); + switch (ret) { + case KNOT_EAGAIN: // Unfinished handshake, continue later. + return KNOT_EOK; + case KNOT_EOK: // Finished handshake, continue with receiving message. + recv = knot_tls_recv_dns(params->tls_conn, rx->iov_base, rx->iov_len); + break; + default: // E.g. handshake timeout. + return ret; + } + } else { + recv = net_dns_tcp_recv(params->socket, rx->iov_base, rx->iov_len, tcp->io_timeout); + } if (recv > 0) { rx->iov_len = recv; } else { - tcp_log_error(params.remote, "receive", recv); + tcp_log_error(params->remote, "receive", recv); return KNOT_EOF; } - handle_query(¶ms, &tcp->layer, rx, NULL); + handle_query(params, &tcp->layer, rx, NULL); /* Resolve until NOOP or finished. */ knot_pkt_t *ans = knot_pkt_new(tx->iov_base, tx->iov_len, tcp->layer.mm); @@ -165,10 +192,15 @@ static int tcp_handle(tcp_context_t *tcp, int fd, const sockaddr_t *remote, knot_layer_produce(&tcp->layer, ans); /* Send, if response generation passed and wasn't ignored. */ if (ans->size > 0 && send_state(tcp->layer.state)) { - int sent = net_dns_tcp_send(fd, ans->wire, ans->size, - tcp->io_timeout, NULL); + int sent; + if (params->tls_conn != NULL) { + sent = knot_tls_send_dns(params->tls_conn, ans->wire, ans->size); + } else { + sent = net_dns_tcp_send(params->socket, ans->wire, ans->size, + tcp->io_timeout, NULL); + } if (sent != ans->size) { - tcp_log_error(params.remote, "send", sent); + tcp_log_error(params->remote, "send", sent); handle_finish(&tcp->layer); return KNOT_EOF; } @@ -222,12 +254,42 @@ static int tcp_event_serve(tcp_context_t *tcp, unsigned i, const iface_t *iface) } } - int ret = tcp_handle(tcp, fd, remote, local, &tcp->iov[0], &tcp->iov[1]); + knotd_qdata_params_t params = params_init(iface->tls ? KNOTD_QUERY_PROTO_TLS + : KNOTD_QUERY_PROTO_TCP, + remote, local, fd, tcp->server, + tcp->thread_id); + + // NOTE there is no way to avoid calling accept() on unwanted connections: + // - it's not possible to read out the remote IP beforehand + // - there is no way to pull it out of the queue + // So we just accept() those connection (possibly going ahead with the handshake) + // and close it immediately. + if (process_query_proto(¶ms, KNOTD_STAGE_PROTO_BEGIN) == KNOTD_PROTO_STATE_BLOCK) { + return KNOT_EDENIED; // results in closing connection + } + + /* Establish a TLS session. */ + if (iface->tls) { + assert(tcp->tls_ctx != NULL); + knot_tls_conn_t *tls_conn = *fdset_ctx2(&tcp->set, i); + if (tls_conn == NULL) { + tls_conn = knot_tls_conn_new(tcp->tls_ctx, fd); + if (tls_conn == NULL) { + return KNOT_ENOMEM; + } + *fdset_ctx2(&tcp->set, i) = tls_conn; + } + params_update_tls(¶ms, tls_conn); + } + + int ret = tcp_handle(tcp, ¶ms, &tcp->iov[0], &tcp->iov[1]); if (ret == KNOT_EOK) { /* Update socket activity timer. */ (void)fdset_set_watchdog(&tcp->set, i, tcp->idle_timeout); } + (void)process_query_proto(¶ms, KNOTD_STAGE_PROTO_END); + return ret; } @@ -273,6 +335,7 @@ static void tcp_wait_for_events(tcp_context_t *tcp) /* Evaluate. */ if (should_close) { + free_tls_ctx(set, idx); fdset_it_remove(&it); } } @@ -325,13 +388,15 @@ int tcp_master(dthread_t *thread) /* Prepare initial buffer for listening and bound sockets. */ if (fdset_init(&tcp.set, FDSET_RESIZE_STEP) != KNOT_EOK) { + ret = KNOT_ENOMEM; goto finish; } /* Set descriptors for the configured interfaces. */ + bool tls = false; tcp.client_threshold = tcp_set_ifaces(handler->server->ifaces, handler->server->n_ifaces, - &tcp.set, thread_id); + &tcp.set, thread_id, &tls); if (tcp.client_threshold == 0) { goto finish; /* Terminate on zero interfaces. */ } @@ -341,6 +406,17 @@ int tcp_master(dthread_t *thread) update_sweep_timer(&next_sweep); update_tcp_conf(&tcp); + /* Initialize TLS context. */ + if (tls) { + // Set the HS timeout to 8x the RMT IO one as the HS duration can be up to 4*roundtrip. + tcp.tls_ctx = knot_tls_ctx_new(handler->server->quic_creds, + tcp.io_timeout, 8 * tcp.io_timeout, true); + if (tcp.tls_ctx == NULL) { + ret = KNOT_ENOMEM; + goto finish; + } + } + for (;;) { /* Check for cancellation. */ if (dt_is_cancelled(thread)) { @@ -359,6 +435,7 @@ int tcp_master(dthread_t *thread) } finish: + knot_tls_ctx_free(tcp.tls_ctx); free(tcp.iov[0].iov_base); free(tcp.iov[1].iov_base); mp_delete(mm.ctx); diff --git a/src/knot/server/udp-handler.c b/src/knot/server/udp-handler.c index e54ce2c..c5166f9 100644 --- a/src/knot/server/udp-handler.c +++ b/src/knot/server/udp-handler.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -73,9 +73,15 @@ typedef struct { static void udp_handler(udp_context_t *udp, knotd_qdata_params_t *params, struct iovec *rx, struct iovec *tx) { + if (process_query_proto(params, KNOTD_STAGE_PROTO_BEGIN) == KNOTD_PROTO_STATE_BLOCK) { + return; + } + // Prepare a reply. struct sockaddr_storage proxied_remote; handle_udp_reply(params, &udp->layer, rx, tx, &proxied_remote); + + (void)process_query_proto(params, KNOTD_STAGE_PROTO_END); } typedef struct { @@ -153,7 +159,7 @@ void cmsg_handle(const struct msghdr *rx, struct msghdr *tx, } struct cmsghdr *cmsg = CMSG_FIRSTHDR(tx); - if (iface->quic) { + if (iface->tls) { *p_ecn = NULL; while (cmsg != NULL) { cmsg_handle_ecn(p_ecn, cmsg); @@ -246,9 +252,9 @@ static void udp_msg_handle(udp_context_t *ctx, const iface_t *iface, void *d) /* Process received pkt. */ knotd_qdata_params_t params = params_init( - iface->quic ? KNOTD_QUERY_PROTO_QUIC : KNOTD_QUERY_PROTO_UDP, + iface->tls ? KNOTD_QUERY_PROTO_QUIC : KNOTD_QUERY_PROTO_UDP, &rq->addr, local, rq->fd, ctx->server, ctx->thread_id); - if (iface->quic) { + if (iface->tls) { #ifdef ENABLE_QUIC quic_handler(¶ms, &ctx->layer, ctx->quic_idle_close, ctx->quic_table, &rq->iov[RX], &rq->msg[TX], p_ecn); @@ -357,9 +363,9 @@ static void udp_mmsg_handle(udp_context_t *ctx, const iface_t *iface, void *d) const sockaddr_t *local = local_addr(&ctx->local, iface); knotd_qdata_params_t params = params_init( - iface->quic ? KNOTD_QUERY_PROTO_QUIC : KNOTD_QUERY_PROTO_UDP, + iface->tls ? KNOTD_QUERY_PROTO_QUIC : KNOTD_QUERY_PROTO_UDP, &rq->addrs[i], local, rq->fd, ctx->server, ctx->thread_id); - if (iface->quic) { + if (iface->tls) { #ifdef ENABLE_QUIC quic_handler(¶ms, &ctx->layer, ctx->quic_idle_close, ctx->quic_table, rx->msg_iov, tx, p_ecn); @@ -432,7 +438,7 @@ static int xdp_mmsg_recv(_unused_ int fd, void *d) static void xdp_mmsg_handle(udp_context_t *ctx, _unused_ const iface_t *iface, void *d) { - assert(!iface->quic); + assert(!iface->tls); xdp_handle_msgs(d, &ctx->layer, ctx->server, ctx->thread_id); } @@ -482,7 +488,6 @@ static int iface_udp_fd(const iface_t *iface, int thread_id, bool xdp_thread, #endif } else { // UDP thread. if (iface->fd_udp_count == 0) { // No UDP interfaces. - assert(iface->fd_xdp_count > 0); return -1; } #ifdef ENABLE_REUSEPORT @@ -508,7 +513,7 @@ static unsigned udp_set_ifaces(const server_t *server, size_t n_ifaces, fdset_t #ifndef ENABLE_REUSEPORT /* If loadbalanced SO_REUSEPORT isn't available, ensure that * just one (first) UDP worker handles the QUIC sockets. */ - if (i->quic && thread_id > 0) { + if (i->tls && thread_id > 0) { continue; } #endif @@ -520,7 +525,7 @@ static unsigned udp_set_ifaces(const server_t *server, size_t n_ifaces, fdset_t if (ret < 0) { return 0; } - if (i->quic) { + if (i->tls) { *quic = true; } } diff --git a/src/knot/server/xdp-handler.c b/src/knot/server/xdp-handler.c index ae8512d..403bb70 100644 --- a/src/knot/server/xdp-handler.c +++ b/src/knot/server/xdp-handler.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -20,6 +20,7 @@ #include <stdlib.h> #include <urcu.h> +#include "knot/nameserver/process_query.h" #include "knot/server/handler.h" #include "knot/server/quic-handler.h" #include "knot/server/xdp-handler.h" @@ -196,6 +197,12 @@ static void handle_udp(xdp_handle_ctx_t *ctx, knot_layer_t *layer, continue; } + params_xdp_update(params, KNOTD_QUERY_PROTO_UDP, msg_recv); + + if (process_query_proto(params, KNOTD_STAGE_PROTO_BEGIN) == KNOTD_PROTO_STATE_BLOCK) { + continue; + } + // Try to allocate a buffer for a reply. if (knot_xdp_reply_alloc(ctx->sock, msg_recv, msg_send) != KNOT_EOK) { if (log_enabled_debug()) { @@ -206,36 +213,50 @@ static void handle_udp(xdp_handle_ctx_t *ctx, knot_layer_t *layer, ctx->msg_udp_count++; // Prepare a reply. - params_xdp_update(params, KNOTD_QUERY_PROTO_UDP, msg_recv, 0, NULL); handle_udp_reply(params, layer, &msg_recv->payload, &msg_send->payload, &proxied_remote); + + (void)process_query_proto(params, KNOTD_STAGE_PROTO_END); } } static void handle_tcp(xdp_handle_ctx_t *ctx, knot_layer_t *layer, knotd_qdata_params_t *params) { - int ret = knot_tcp_recv(ctx->relays, ctx->msg_recv, ctx->msg_recv_count, - ctx->tcp_table, ctx->syn_table, XDP_TCP_IGNORE_NONE); - if (ret != KNOT_EOK) { - if (log_enabled_debug()) { - log_debug("TCP/XDP, failed to process some packets (%s)", knot_strerror(ret)); - } - return; - } else if (knot_tcp_relay_empty(&ctx->relays[0])) { // no TCP traffic - return; - } uint8_t ans_buf[KNOT_WIRE_MAX_PKTSIZE]; for (uint32_t i = 0; i < ctx->msg_recv_count; i++) { + knot_xdp_msg_t *msg_recv = &ctx->msg_recv[i]; knot_tcp_relay_t *rl = &ctx->relays[i]; + if (!(msg_recv->flags & KNOT_XDP_MSG_TCP)) { + continue; + } + + params_xdp_update(params, KNOTD_QUERY_PROTO_TCP, msg_recv); + + if (process_query_proto(params, KNOTD_STAGE_PROTO_BEGIN) == KNOTD_PROTO_STATE_BLOCK) { + continue; + } + + int ret = knot_tcp_recv(rl, msg_recv, ctx->tcp_table, + ctx->syn_table, XDP_TCP_IGNORE_NONE); + if (ret != KNOT_EOK) { + if (log_enabled_debug()) { + log_debug("TCP/XDP, failed to process some packets (%s)", + knot_strerror(ret)); + } + continue; + } else if (knot_tcp_relay_empty(rl)) { + continue; + } + + params_update_tcp(params, rl->conn->establish_rtt); + // Process all complete DNS queries in one TCP stream. for (size_t j = 0; rl->inbf != NULL && j < rl->inbf->n_inbufs; j++) { // Consume the query. - params_xdp_update(params, KNOTD_QUERY_PROTO_TCP, ctx->msg_recv, - rl->conn->establish_rtt, NULL); struct iovec *inbufs = rl->inbf->inbufs; handle_query(params, layer, &inbufs[j], NULL); @@ -253,6 +274,8 @@ static void handle_tcp(xdp_handle_ctx_t *ctx, knot_layer_t *layer, handle_finish(layer); } + + (void)process_query_proto(params, KNOTD_STAGE_PROTO_END); } } @@ -274,6 +297,12 @@ static void handle_quic(xdp_handle_ctx_t *ctx, knot_layer_t *layer, continue; } + params_xdp_update(params, KNOTD_QUERY_PROTO_QUIC, msg_recv); + + if (process_query_proto(params, KNOTD_STAGE_PROTO_BEGIN) == KNOTD_PROTO_STATE_BLOCK) { + continue; + } + knot_quic_reply_t *reply = &ctx->quic_replies[i]; knot_xdp_msg_t *msg_out = &ctx->msg_send_udp[i]; @@ -289,7 +318,9 @@ static void handle_quic(xdp_handle_ctx_t *ctx, knot_layer_t *layer, &ctx->quic_relays[i]); knot_quic_conn_t *conn = ctx->quic_relays[i]; - handle_quic_streams(conn, params, layer, &ctx->msg_recv[i]); + handle_quic_streams(conn, params, layer); + + (void)process_query_proto(params, KNOTD_STAGE_PROTO_END); } #else (void)(ctx); diff --git a/src/knot/updates/acl.c b/src/knot/updates/acl.c index d297747..456e8bb 100644 --- a/src/knot/updates/acl.c +++ b/src/knot/updates/acl.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -18,16 +18,13 @@ #include "contrib/string.h" #include "contrib/wire_ctx.h" -#ifdef ENABLE_QUIC -#include "libknot/quic/quic.h" -#endif // ENABLE_QUIC static bool cert_pin_check(const uint8_t *session_pin, size_t session_pin_size, conf_val_t *pins) { if (pins->code == KNOT_ENOENT) { // No certificate pin authentication required. return true; - } else if (session_pin_size == 0) { // Not a QUIC connection. + } else if (session_pin_size == 0) { // Not a TLS/QUIC connection. return false; } @@ -283,20 +280,15 @@ static bool check_addr_key(conf_t *conf, conf_val_t *addr_val, conf_val_t *key_v bool acl_allowed(conf_t *conf, conf_val_t *acl, acl_action_t action, const struct sockaddr_storage *addr, knot_tsig_key_t *tsig, const knot_dname_t *zone_name, knot_pkt_t *query, - struct knot_quic_conn *conn) + struct gnutls_session_int *tls_session) { if (acl == NULL || addr == NULL || tsig == NULL) { return false; } -#ifdef ENABLE_QUIC - uint8_t session_pin[KNOT_QUIC_PIN_LEN]; + uint8_t session_pin[KNOT_TLS_PIN_LEN]; size_t session_pin_size = sizeof(session_pin); - knot_quic_conn_pin(conn, session_pin, &session_pin_size, false); -#else - uint8_t session_pin[1]; - size_t session_pin_size = 0; -#endif // ENABLE_QUIC + knot_tls_pin(tls_session, session_pin, &session_pin_size, false); bool forward = false; if (action == ACL_ACTION_UPDATE) { @@ -392,20 +384,15 @@ next_acl: } bool rmt_allowed(conf_t *conf, conf_val_t *rmts, const struct sockaddr_storage *addr, - knot_tsig_key_t *tsig, struct knot_quic_conn *conn) + knot_tsig_key_t *tsig, struct gnutls_session_int *tls_session) { if (!conf->cache.srv_auto_acl) { return false; } -#ifdef ENABLE_QUIC - uint8_t session_pin[KNOT_QUIC_PIN_LEN]; + uint8_t session_pin[KNOT_TLS_PIN_LEN]; size_t session_pin_size = sizeof(session_pin); - knot_quic_conn_pin(conn, session_pin, &session_pin_size, false); -#else - uint8_t session_pin[1]; - size_t session_pin_size = 0; -#endif // ENABLE_QUIC + knot_tls_pin(tls_session, session_pin, &session_pin_size, false); conf_mix_iter_t iter; conf_mix_iter_init(conf, rmts, &iter); diff --git a/src/knot/updates/acl.h b/src/knot/updates/acl.h index 88d7de5..5072a29 100644 --- a/src/knot/updates/acl.h +++ b/src/knot/updates/acl.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -19,6 +19,7 @@ #include <stdbool.h> #include <sys/socket.h> +#include "libknot/quic/tls_common.h" #include "libknot/tsig.h" #include "knot/conf/conf.h" @@ -51,21 +52,21 @@ typedef enum { * * If a proper ACL rule is found and tsig.name is not empty, tsig.secret is filled. * - * \param conf Configuration. - * \param acl Pointer to ACL config multivalued identifier. - * \param action ACL action. - * \param addr IP address. - * \param tsig TSIG parameters. - * \param zone_name Zone name. - * \param query Update query. - * \param conn Possible QUIC connection. + * \param conf Configuration. + * \param acl Pointer to ACL config multivalued identifier. + * \param action ACL action. + * \param addr IP address. + * \param tsig TSIG parameters. + * \param zone_name Zone name. + * \param query Update query. + * \param tls_session Possible TLS session. * * \retval True if authenticated. */ bool acl_allowed(conf_t *conf, conf_val_t *acl, acl_action_t action, const struct sockaddr_storage *addr, knot_tsig_key_t *tsig, const knot_dname_t *zone_name, knot_pkt_t *query, - struct knot_quic_conn *conn); + struct gnutls_session_int *tls_session); /*! * \brief Checks if the address and/or tsig key matches a remote from the list. @@ -75,13 +76,13 @@ bool acl_allowed(conf_t *conf, conf_val_t *acl, acl_action_t action, * * If a proper REMOTE is found and tsig.name is not empty, tsig.secret is filled. * - * \param conf Configuration. - * \param rmts Pointer to REMOTE config multivalued identifier. - * \param addr IP address. - * \param tsig TSIG parameters. - * \param conn Possible QUIC connection. + * \param conf Configuration. + * \param rmts Pointer to REMOTE config multivalued identifier. + * \param addr IP address. + * \param tsig TSIG parameters. + * \param tls_session Possible TLS session. * * \retval True if authenticated. */ bool rmt_allowed(conf_t *conf, conf_val_t *rmts, const struct sockaddr_storage *addr, - knot_tsig_key_t *tsig, struct knot_quic_conn *conn); + knot_tsig_key_t *tsig, struct gnutls_session_int *tls_session); diff --git a/src/knot/updates/ddns.c b/src/knot/updates/ddns.c index 5ab858f..47e3fc5 100644 --- a/src/knot/updates/ddns.c +++ b/src/knot/updates/ddns.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -266,21 +266,41 @@ static bool node_contains_rr(const zone_node_t *node, /*!< \brief Returns true if CNAME is in this node. */ static bool adding_to_cname(const knot_dname_t *owner, + zone_update_t *update, const zone_node_t *node) { if (node == NULL) { - // Node did not exist before update. + // Node did not exist before update, juch check DNAMEs above. + + while ((owner = knot_dname_next_label(owner)) != NULL && + (node = zone_update_get_node(update, owner)) == NULL); + + for ( ; node != NULL; node = node->parent) { + knot_rrset_t dname = node_rrset(node, KNOT_RRTYPE_DNAME); + if (!knot_rrset_empty(&dname)) { + // DNAME above + return true; + } + } + return false; } knot_rrset_t cname = node_rrset(node, KNOT_RRTYPE_CNAME); - if (knot_rrset_empty(&cname)) { - // Node did not contain CNAME before update. - return false; + if (!knot_rrset_empty(&cname)) { + // CNAME present + return true; } - // CNAME present - return true; + while ((node = node->parent) != NULL) { + knot_rrset_t dname = node_rrset(node, KNOT_RRTYPE_DNAME); + if (!knot_rrset_empty(&dname)) { + // DNAME above + return true; + } + } + + return false; } /*!< \brief Used to ignore SOA deletions and SOAs with lower serial than zone. */ @@ -315,12 +335,29 @@ static int add_rr_to_changeset(const knot_rrset_t *rr, zone_update_t *update) return zone_update_add(update, rr); } -/*!< \brief Processes CNAME addition (replace or ignore) */ +int node_empty_cb(zone_node_t *node, _unused_ void *ctx) +{ + return node_empty(node) ? KNOT_EOK : KNOT_ESEMCHECK; +} + +bool subtree_empty(zone_contents_t *zone, const zone_node_t *node) +{ + if (node == NULL) { + return true; + } + int ret = zone_tree_sub_apply(zone->nodes, node->owner, true, node_empty_cb, NULL); + return (ret == KNOT_EOK); +} + +/*!< \brief Processes CNAME/DNAME addition (replace or ignore) */ static int process_add_cname(const zone_node_t *node, const knot_rrset_t *rr, + uint16_t type, zone_update_t *update) { - knot_rrset_t cname = node_rrset(node, KNOT_RRTYPE_CNAME); + assert(type == KNOT_RRTYPE_CNAME || type == KNOT_RRTYPE_DNAME); + + knot_rrset_t cname = node_rrset(node, type); if (!knot_rrset_empty(&cname)) { // If they are identical, ignore. if (knot_rrset_equal(&cname, rr, true)) { @@ -333,40 +370,24 @@ static int process_add_cname(const zone_node_t *node, } return add_rr_to_changeset(rr, update); - } else if (!node_empty(node)) { + } else if (type == KNOT_RRTYPE_CNAME && !node_empty(node)) { // Other occupied node => ignore. return KNOT_EOK; + } else if (type == KNOT_RRTYPE_DNAME && !subtree_empty(update->new_cont, node)) { + // Equivalent to above, ignore. + return KNOT_EOK; + } else if (type == KNOT_RRTYPE_DNAME && node_rrtype_exists(node, KNOT_RRTYPE_CNAME)) { + // RFC 6672 §5.2. + return KNOT_EOK; + } else if (type == KNOT_RRTYPE_CNAME && adding_to_cname(rr->owner, update, node)) { + // DNAME exists above CNAME, ignore. + return KNOT_EOK; } else { // Can add. return add_rr_to_changeset(rr, update); } } -/*!< \brief Processes NSEC3PARAM addition (ignore when not removed, or non-apex) */ -static int process_add_nsec3param(const zone_node_t *node, - const knot_rrset_t *rr, - zone_update_t *update) -{ - if (node == NULL || !node_rrtype_exists(node, KNOT_RRTYPE_SOA)) { - // Ignore non-apex additions - char *owner = knot_dname_to_str_alloc(rr->owner); - log_warning("DDNS, refusing to add NSEC3PARAM to non-apex " - "node '%s'", owner); - free(owner); - return KNOT_EDENIED; - } - knot_rrset_t param = node_rrset(node, KNOT_RRTYPE_NSEC3PARAM); - if (knot_rrset_empty(¶m)) { - return add_rr_to_changeset(rr, update); - } - - char *owner = knot_dname_to_str_alloc(rr->owner); - log_warning("DDNS, refusing to add second NSEC3PARAM to node '%s'", owner); - free(owner); - - return KNOT_EOK; -} - /*! * \brief Processes SOA addition (ignore when non-apex), lower serials * dropped before. @@ -395,7 +416,7 @@ static int process_add_normal(const zone_node_t *node, const knot_rrset_t *rr, zone_update_t *update) { - if (adding_to_cname(rr->owner, node)) { + if (adding_to_cname(rr->owner, update, node)) { // Adding RR to CNAME node, ignore. return KNOT_EOK; } @@ -415,11 +436,10 @@ static int process_add(const knot_rrset_t *rr, { switch(rr->type) { case KNOT_RRTYPE_CNAME: - return process_add_cname(node, rr, update); + case KNOT_RRTYPE_DNAME: + return process_add_cname(node, rr, rr->type, update); case KNOT_RRTYPE_SOA: return process_add_soa(node, rr, update); - case KNOT_RRTYPE_NSEC3PARAM: - return process_add_nsec3param(node, rr, update); default: return process_add_normal(node, rr, update); } @@ -531,49 +551,32 @@ static int process_remove(const knot_rrset_t *rr, } } -/*!< \brief Checks whether addition has not violated DNAME rules. */ -static bool sem_check(const knot_rrset_t *rr, const zone_node_t *zone_node, - zone_update_t *update) -{ - const zone_node_t *added_node = zone_contents_find_node(update->new_cont, rr->owner); - - // we do this sem check AFTER adding the RR, so the node must exist - assert(added_node != NULL); - - for (const zone_node_t *parent = added_node->parent; - parent != NULL; parent = parent->parent) { - if (node_rrtype_exists(parent, KNOT_RRTYPE_DNAME)) { - // Parent has DNAME RRSet, refuse update - return false; - } - } - - if (rr->type != KNOT_RRTYPE_DNAME || zone_node == NULL) { - return true; - } - - // Check that we have not created node with DNAME children. - if (zone_node->children > 0) { - // Updated node has children and DNAME was added, refuse update - return false; - } - - return true; -} - /*!< \brief Checks whether we can accept this RR. */ static int check_update(const knot_rrset_t *rrset, const knot_pkt_t *query, - uint16_t *rcode) + const zone_contents_t *zone, uint16_t *rcode) { /* Accept both subdomain and dname match. */ const knot_dname_t *owner = rrset->owner; const knot_dname_t *qname = knot_pkt_qname(query); + assert(knot_dname_is_equal(qname, zone->apex->owner)); const int in_bailiwick = knot_dname_in_bailiwick(owner, qname); if (in_bailiwick < 0) { *rcode = KNOT_RCODE_NOTZONE; return KNOT_EOUTOFZONE; } + if (rrset->type == KNOT_RRTYPE_NSEC3PARAM) { + if (!knot_dname_is_equal(rrset->owner, zone->apex->owner)) { + log_warning("DDNS, refusing to add NSEC3PARAM to non-apex node"); + *rcode = KNOT_RCODE_REFUSED; + return KNOT_EDENIED; + } else if (node_rrtype_exists(zone->apex, rrset->type)) { + log_warning("DDNS, refusing to add second NSEC3PARAM to zone apex"); + *rcode = KNOT_RCODE_REFUSED; + return KNOT_EDENIED; + } + } + if (rrset->rclass == knot_pkt_qclass(query)) { if (knot_rrtype_is_metatype(rrset->type)) { *rcode = KNOT_RCODE_FORMERR; @@ -605,13 +608,7 @@ static int process_rr(const knot_rrset_t *rr, zone_update_t *update) const zone_node_t *node = zone_update_get_node(update, rr->owner); if (is_addition(rr)) { - int ret = process_add(rr, node, update); - if (ret == KNOT_EOK) { - if (!sem_check(rr, node, update)) { - return KNOT_EDENIED; - } - } - return ret; + return process_add(rr, node, update); } else if (is_removal(rr)) { return process_remove(rr, node, update); } else { @@ -660,6 +657,27 @@ int ddns_process_prereqs(const knot_pkt_t *query, zone_update_t *update, return ret; } +int ddns_precheck_update(const knot_pkt_t *query, zone_update_t *update, + uint16_t *rcode) +{ + if (query == NULL || rcode == NULL || update == NULL) { + return KNOT_EINVAL; + } + + // Check all RRs in the authority section. + const knot_pktsection_t *authority = knot_pkt_section(query, KNOT_AUTHORITY); + const knot_rrset_t *authority_rr = (authority->count > 0) ? knot_pkt_rr(authority, 0) : NULL; + for (uint16_t i = 0; i < authority->count; ++i) { + int ret = check_update(&authority_rr[i], query, update->new_cont, rcode); + if (ret != KNOT_EOK) { + assert(*rcode != KNOT_RCODE_NOERROR); + return ret; + } + } + + return KNOT_EOK; +} + int ddns_process_update(const knot_pkt_t *query, zone_update_t *update, uint16_t *rcode) { @@ -677,18 +695,11 @@ int ddns_process_update(const knot_pkt_t *query, zone_update_t *update, const knot_rrset_t *authority_rr = (authority->count > 0) ? knot_pkt_rr(authority, 0) : NULL; for (uint16_t i = 0; i < authority->count; ++i) { const knot_rrset_t *rr = &authority_rr[i]; - // Check if RR is correct. - int ret = check_update(rr, query, rcode); - if (ret != KNOT_EOK) { - assert(*rcode != KNOT_RCODE_NOERROR); - return ret; - } - if (skip_soa(rr, sn_old)) { continue; } - ret = process_rr(rr, update); + int ret = process_rr(rr, update); if (ret != KNOT_EOK) { *rcode = ret_to_rcode(ret); return ret; diff --git a/src/knot/updates/ddns.h b/src/knot/updates/ddns.h index d5661f5..40f1b37 100644 --- a/src/knot/updates/ddns.h +++ b/src/knot/updates/ddns.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -32,6 +32,18 @@ int ddns_process_prereqs(const knot_pkt_t *query, zone_update_t *update, uint16_t *rcode); /*! + * \brief Performs a pre-check of the update'S sanity. + * + * \param query DNS message containing the update. + * \param update Zone to be checked. + * \param rcode Returned DNS RCODE. + * + * \return KNOT_E* + */ +int ddns_precheck_update(const knot_pkt_t *query, zone_update_t *update, + uint16_t *rcode); + +/*! * \brief Processes DNS update and creates a changeset out of it. Zone is left * intact. * diff --git a/src/knot/updates/zone-update.c b/src/knot/updates/zone-update.c index 73c9558..4b65a2c 100644 --- a/src/knot/updates/zone-update.c +++ b/src/knot/updates/zone-update.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -19,8 +19,8 @@ #include <urcu.h> #include "knot/catalog/interpret.h" +#include "knot/common/dbus.h" #include "knot/common/log.h" -#include "knot/common/systemd.h" #include "knot/dnssec/zone-events.h" #include "knot/server/server.h" #include "knot/updates/zone-update.h" @@ -942,26 +942,10 @@ int zone_update_commit(conf_t *conf, zone_update_t *update) val = conf_zone_get(conf, C_DNSSEC_VALIDATION, update->zone->name); if (conf_bool(&val)) { bool incr_valid = update->flags & UPDATE_INCREMENTAL; - const char *msg_valid = incr_valid ? "incremental " : ""; - - ret = knot_dnssec_validate_zone(update, conf, 0, incr_valid); + ret = knot_dnssec_validate_zone(update, conf, 0, incr_valid, true); if (ret != KNOT_EOK) { - log_zone_error(update->zone->name, "DNSSEC, %svalidation failed (%s)", - msg_valid, knot_strerror(ret)); - char type_str[16]; - knot_dname_txt_storage_t name_str; - if (knot_dname_to_str(name_str, update->validation_hint.node, sizeof(name_str)) != NULL && - knot_rrtype_to_string(update->validation_hint.rrtype, type_str, sizeof(type_str)) >= 0) { - log_zone_error(update->zone->name, "DNSSEC, validation hint: %s %s", - name_str, type_str); - } discard_adds_tree(update); - if (conf->cache.srv_dbus_event & DBUS_EVENT_ZONE_INVALID) { - systemd_emit_zone_invalid(update->zone->name); - } return ret; - } else { - log_zone_info(update->zone->name, "DNSSEC, %svalidation successful", msg_valid); } } @@ -1023,8 +1007,8 @@ int zone_update_commit(conf_t *conf, zone_update_t *update) } if (conf->cache.srv_dbus_event & DBUS_EVENT_ZONE_UPDATED) { - systemd_emit_zone_updated(update->zone->name, - zone_contents_serial(update->zone->contents)); + dbus_emit_zone_updated(update->zone->name, + zone_contents_serial(update->zone->contents)); } memset(update, 0, sizeof(*update)); diff --git a/src/knot/updates/zone-update.h b/src/knot/updates/zone-update.h index 0499d72..814d0ec 100644 --- a/src/knot/updates/zone-update.h +++ b/src/knot/updates/zone-update.h @@ -25,7 +25,9 @@ typedef struct { knot_dname_storage_t next; const knot_dname_t *node; + uint32_t remaining_secs; uint16_t rrtype; + int warning; } dnssec_validation_hint_t; /*! \brief Structure for zone contents updating / querying. */ diff --git a/src/knot/zone/backup.c b/src/knot/zone/backup.c index 36fd577..5c3038a 100644 --- a/src/knot/zone/backup.c +++ b/src/knot/zone/backup.c @@ -85,6 +85,7 @@ int zone_backup_init(bool restore_mode, knot_backup_params_t filters, bool force ctx->restore_mode = restore_mode; ctx->backup_params = filters; ctx->in_backup = 0; // Just to be sure. + ctx->arch_match = true; ctx->forced = forced; ctx->backup_format = BACKUP_VERSION; ctx->backup_global = false; @@ -105,6 +106,11 @@ int zone_backup_init(bool restore_mode, knot_backup_params_t filters, bool force // For restore, check that there are all required data components in the backup. if (restore_mode) { + if (!ctx->arch_match && filters & BACKUP_PARAM_DB) { + free(ctx); + return KNOT_ECPUCOMPAT; + } + // '+kaspdb' in backup provides data also for '+keysonly' restore. knot_backup_params_t available = ctx->in_backup | ((bool)(ctx->in_backup & BACKUP_PARAM_KASPDB) * BACKUP_PARAM_KEYSONLY); @@ -369,7 +375,7 @@ static int backup_keystore(conf_t *conf, zone_t *zone, zone_backup_ctx_t *ctx) return ret; } if (backend_type == KEYSTORE_BACKEND_PKCS11) { - log_zone_notice(zone->name, "private keys from PKCS #11 aren't subject of backup/restore"); + log_zone_notice(zone->name, "private keys from PKCS #11 are not subject of backup/restore"); (void)dnssec_keystore_deinit(from); return KNOT_EOK; } diff --git a/src/knot/zone/backup.h b/src/knot/zone/backup.h index 9f2660d..ad0c954 100644 --- a/src/knot/zone/backup.h +++ b/src/knot/zone/backup.h @@ -57,6 +57,11 @@ typedef enum { BACKUP_PARAM_TIMERS | BACKUP_PARAM_KASPDB | \ BACKUP_PARAM_CATALOG) +/*! \bref Backup components using LMDB databases. */ +#define BACKUP_PARAM_DB (BACKUP_PARAM_JOURNAL | BACKUP_PARAM_TIMERS | \ + BACKUP_PARAM_KASPDB | BACKUP_PARAM_KEYSONLY | \ + BACKUP_PARAM_CATALOG) + typedef struct { const char *name; knot_backup_params_t param; @@ -70,6 +75,7 @@ typedef struct zone_backup_ctx { bool forced; // if true, the force flag has been set knot_backup_params_t backup_params; // bit-mapped list of backup components knot_backup_params_t in_backup; // bit-mapped list of components available in backup + bool arch_match; // match of the system and the backup architectures bool backup_global; // perform global backup for all zones ssize_t readers; // when decremented to 0, all zones done, free this context pthread_mutex_t readers_mutex; // mutex covering readers counter diff --git a/src/knot/zone/backup_dir.c b/src/knot/zone/backup_dir.c index 7bf9fd5..b382258 100644 --- a/src/knot/zone/backup_dir.c +++ b/src/knot/zone/backup_dir.c @@ -28,11 +28,21 @@ #include "contrib/getline.h" #include "knot/common/log.h" +#ifdef ENDIANITY_LITTLE + #define ENDIAN_STR "LE" +#else + #define ENDIAN_STR "BE" +#endif +#define _STR(x) #x +#define STR(x) _STR(x) +#define KNOT_ARCH STR(__LONG_WIDTH__) ENDIAN_STR + #define LABEL_FILE "knot_backup.label" #define LOCK_FILE "lock.knot_backup" #define LABEL_FILE_HEAD "label: Knot DNS Backup\n" #define LABEL_FILE_FORMAT "backup_format: %d\n" +#define LABEL_FILE_ARCH "architecture: " #define LABEL_FILE_PARAMS "parameters: " #define LABEL_FILE_BACKUPDIR "backupdir " #define LABEL_FILE_TIME_FORMAT "%Y-%m-%d %H:%M:%S %Z" @@ -49,6 +59,7 @@ static const char *label_file_name = LABEL_FILE; static const char *lock_file_name = LOCK_FILE; static const char *label_file_head = LABEL_FILE_HEAD; +static const char *label_file_arch = KNOT_ARCH; static void get_full_path(zone_backup_ctx_t *ctx, const char *filename, char *full_path, size_t full_path_size) @@ -125,6 +136,9 @@ static int make_label_file(zone_backup_ctx_t *ctx) localtime_r(&now, &tm); strftime(finished_time, sizeof(finished_time), LABEL_FILE_TIME_FORMAT, &tm); + int lmdb_major, lmdb_minor, lmdb_patch; + (void)mdb_version(&lmdb_major, &lmdb_minor, &lmdb_patch); + // Print the label contents. char params_str[PARAMS_MAX_LENGTH]; print_params(params_str, ctx->backup_params); @@ -135,10 +149,14 @@ static int make_label_file(zone_backup_ctx_t *ctx) "started_time: %s\n" "finished_time: %s\n" "knot_version: %s\n" + "lmdb_version: %d.%d.%d\n" + LABEL_FILE_ARCH "%s\n" LABEL_FILE_PARAMS "%s+" LABEL_FILE_BACKUPDIR "%s\n" "zone_count: %d\n", label_file_head, - ctx->backup_format, ident, started_time, finished_time, PACKAGE_VERSION, + ctx->backup_format, ident, started_time, finished_time, + PACKAGE_VERSION, + lmdb_major, lmdb_minor, lmdb_patch, label_file_arch, params_str, ctx->backup_dir, ctx->zone_count); @@ -199,6 +217,7 @@ static int get_backup_format(zone_backup_ctx_t *ctx) unsigned int remain = 3; // Bit-mapped "punch card" for lines to get data from. while (remain > 0 && knot_getline(&line, &line_size, file) != -1) { int value; + char str[8]; if (sscanf(line, LABEL_FILE_FORMAT, &value) != 0) { if (value >= BACKUP_FORMAT_TERM) { ret = KNOT_ENOTSUP; @@ -212,6 +231,11 @@ static int get_backup_format(zone_backup_ctx_t *ctx) continue; } } + if (sscanf(line, LABEL_FILE_ARCH "%7s\n", str) != 0 && + strcmp(str, label_file_arch) != 0) { + ctx->arch_match = false; + continue; + } if (strncmp(line, LABEL_FILE_PARAMS, sizeof(LABEL_FILE_PARAMS) - 1) == 0) { ctx->in_backup = parse_params(line + sizeof(LABEL_FILE_PARAMS) - 1); remain &= ~2; @@ -240,6 +264,22 @@ int backupdir_init(zone_backup_ctx_t *ctx) return KNOT_ENOTDIR; } } else { + if (ctx->forced) { + if (stat(ctx->backup_dir, &sb) == 0) { + int ret2 = remove_path(ctx->backup_dir, S_ISDIR(sb.st_mode)); + if (ret2 != KNOT_EOK) { + return ret2; + } + } else if (errno != ENOENT) { + return knot_map_errno(); + } else if (lstat(ctx->backup_dir, &sb) == 0 && S_ISLNK(sb.st_mode)) { + // Stale symlink. + if (unlink(ctx->backup_dir) != 0) { + return knot_map_errno(); + } + } // Omitting lstat() failure check, make_dir() will do it. + } + ret = make_dir(ctx->backup_dir, S_IRWXU | S_IRWXG, true); if (ret != KNOT_EOK) { return ret; diff --git a/src/knot/zone/contents.c b/src/knot/zone/contents.c index cba13e8..262136b 100644 --- a/src/knot/zone/contents.c +++ b/src/knot/zone/contents.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -106,6 +106,12 @@ static zone_node_t *get_nsec3_node(const zone_contents_t *zone, return zone_tree_get(zone->nsec3_nodes, name); } +// UBSAN type punning workaround +static zone_node_t *node_new_for_contents_wrap(const uint8_t *owner, void *contents) +{ + return node_new_for_contents(owner, contents); +} + static int insert_rr(zone_contents_t *z, const knot_rrset_t *rr, zone_node_t **n) { if (knot_rrset_empty(rr)) { @@ -114,7 +120,7 @@ static int insert_rr(zone_contents_t *z, const knot_rrset_t *rr, zone_node_t **n if (*n == NULL) { int ret = zone_tree_add_node(zone_contents_tree_for_rr(z, rr), z->apex, rr->owner, - (zone_tree_new_node_cb_t)node_new_for_contents, z, n); + node_new_for_contents_wrap, z, n); if (ret != KNOT_EOK) { return ret; } diff --git a/src/knot/zone/contents.h b/src/knot/zone/contents.h index 8f1f160..f344c97 100644 --- a/src/knot/zone/contents.h +++ b/src/knot/zone/contents.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -16,6 +16,7 @@ #pragma once +#include "contrib/time.h" #include "libdnssec/nsec.h" #include "libknot/rrtype/nsec3param.h" #include "knot/zone/node.h" @@ -38,6 +39,7 @@ typedef struct zone_contents { size_t size; uint32_t max_ttl; bool dnssec; + knot_time_t dnssec_expire; } zone_contents_t; /*! diff --git a/src/knot/zone/digest.c b/src/knot/zone/digest.c index b961f15..a4d50ce 100644 --- a/src/knot/zone/digest.c +++ b/src/knot/zone/digest.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -60,7 +60,7 @@ static int digest_rrset(knot_rrset_t *rrset, const zone_node_t *node, void *vctx } } - size_t buf_req = knot_rrset_size(rrset); + size_t buf_req = knot_rrset_size_estimate(rrset); if (buf_req > ctx->buf_size) { uint8_t *newbuf = realloc(ctx->buf, buf_req); if (newbuf == NULL) { @@ -71,7 +71,7 @@ static int digest_rrset(knot_rrset_t *rrset, const zone_node_t *node, void *vctx } int ret = knot_rrset_to_wire_extra(rrset, ctx->buf, ctx->buf_size, 0, - NULL, KNOT_PF_ORIGTTL | KNOT_PF_BUFENOUGH); + NULL, KNOT_PF_ORIGTTL); // cleanup apex RRSIGs mess if (node == ctx->apex && rrset->type == KNOT_RRTYPE_RRSIG) { diff --git a/src/knot/zone/semantic-check.c b/src/knot/zone/semantic-check.c index 92ad29c..3d085d8 100644 --- a/src/knot/zone/semantic-check.c +++ b/src/knot/zone/semantic-check.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -29,6 +29,8 @@ static const char *error_messages[SEM_ERR_UNKNOWN + 1] = { [SEM_ERR_SOA_NONE] = "missing SOA at the zone apex", + [SEM_ERR_SOA_MULTIPLE] = + "multiple SOA records", [SEM_ERR_CNAME_EXTRA_RECORDS] = "another record exists beside CNAME", @@ -516,7 +518,7 @@ static sem_error_t err_dnssec2sem(int ret, uint16_t rrtype, char *info, size_t l static int verify_dnssec(zone_contents_t *zone, sem_handler_t *handler, time_t time) { zone_update_t fake_up = { .new_cont = zone, }; - int ret = knot_dnssec_validate_zone(&fake_up, NULL, time, false); + int ret = knot_dnssec_validate_zone(&fake_up, NULL, time, false, false); if (fake_up.validation_hint.node != NULL) { // validation found an issue char info[64] = ""; sem_error_t err = err_dnssec2sem(ret, fake_up.validation_hint.rrtype, info, sizeof(info)); diff --git a/src/knot/zone/semantic-check.h b/src/knot/zone/semantic-check.h index 230c709..a0b1d21 100644 --- a/src/knot/zone/semantic-check.h +++ b/src/knot/zone/semantic-check.h @@ -35,6 +35,7 @@ typedef enum { typedef enum { // Mandatory checks. SEM_ERR_SOA_NONE, + SEM_ERR_SOA_MULTIPLE, SEM_ERR_CNAME_EXTRA_RECORDS, SEM_ERR_CNAME_MULTIPLE, diff --git a/src/knot/zone/zone-tree.c b/src/knot/zone/zone-tree.c index 87dde18..c3f79e7 100644 --- a/src/knot/zone/zone-tree.c +++ b/src/knot/zone/zone-tree.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -241,7 +241,7 @@ int zone_tree_add_node(zone_tree_t *tree, zone_node_t *apex, const knot_dname_t return ret; } zone_node_t *parent = NULL; - ret = zone_tree_add_node(tree, apex, knot_wire_next_label(dname, NULL), new_cb, new_cb_ctx, &parent); + ret = zone_tree_add_node(tree, apex, knot_dname_next_label(dname), new_cb, new_cb_ctx, &parent); if (ret != KNOT_EOK) { return ret; } diff --git a/src/knot/zone/zone.c b/src/knot/zone/zone.c index 7c84202..06a8a90 100644 --- a/src/knot/zone/zone.c +++ b/src/knot/zone/zone.c @@ -180,6 +180,7 @@ zone_t* zone_new(const knot_dname_t *name) zone->ddns_queue_size = 0; init_list(&zone->ddns_queue); + pthread_mutex_init(&zone->cu_lock, NULL); knot_sem_init(&zone->cow_lock, 1); // Preferred master lock @@ -222,6 +223,7 @@ void zone_free(zone_t **zone_ptr) free_ddns_queue(zone); pthread_mutex_destroy(&zone->ddns_lock); + pthread_mutex_destroy(&zone->cu_lock); knot_sem_destroy(&zone->cow_lock); /* Control update. */ @@ -273,6 +275,12 @@ void zone_reset(conf_t *conf, zone_t *zone) } \ } +// UBSAN type punning workaround +static bool dname_cmp_sweep_wrap(const uint8_t *zone, void *data) +{ + return knot_dname_cmp((const knot_dname_t *)zone, (const knot_dname_t *)data) != 0; +} + int selective_zone_purge(conf_t *conf, zone_t *zone, purge_flag_t params) { if (conf == NULL || zone == NULL) { @@ -291,7 +299,7 @@ int selective_zone_purge(conf_t *conf, zone_t *zone, purge_flag_t params) zone_timers_sanitize(conf, zone); zone->zonefile.bootstrap_cnt = 0; ret = zone_timers_sweep(&zone->server->timerdb, - (sweep_cb)knot_dname_cmp, zone->name); + dname_cmp_sweep_wrap, zone->name); RETURN_IF_FAILED("timers", KNOT_ENOENT); } diff --git a/src/knot/zone/zone.h b/src/knot/zone/zone.h index 0527c85..a6046de 100644 --- a/src/knot/zone/zone.h +++ b/src/knot/zone/zone.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -16,6 +16,7 @@ #pragma once +#include "contrib/atomic.h" #include "contrib/semaphore.h" #include "knot/catalog/catalog_update.h" #include "knot/conf/conf.h" @@ -114,6 +115,7 @@ typedef struct zone /*! \brief Control update context. */ struct zone_update *control_update; + pthread_mutex_t cu_lock; /*! \brief Ensue one COW transaction on zone's trees at a time. */ knot_sem_t cow_lock; @@ -122,7 +124,7 @@ typedef struct zone struct server *server; /*! \brief Zone backup context (NULL unless backup pending). */ - struct zone_backup_ctx *backup_ctx; + knot_atomic_ptr_t backup_ctx; /*! \brief Catalog-generate feature. */ knot_dname_t *catalog_gen; diff --git a/src/knot/zone/zonedb-load.c b/src/knot/zone/zonedb-load.c index d8acd0b..52d9b0f 100644 --- a/src/knot/zone/zonedb-load.c +++ b/src/knot/zone/zonedb-load.c @@ -510,7 +510,7 @@ static knot_zonedb_t *create_zonedb(conf_t *conf, server_t *server, reload_t mod if (forw == NULL) { knot_dname_txt_storage_t forw_str; (void)knot_dname_to_str(forw_str, forw_name, sizeof(forw_str)); - log_zone_warning(z->name, "zone to reverse %s doesn't exist", + log_zone_warning(z->name, "zone to reverse %s does not exist", forw_str); } else { z->reverse_from = forw; @@ -587,6 +587,12 @@ catalog_only: } } +// UBSAN type punning workaround +static void zone_contents_deep_free_wrap(void *contents) +{ + zone_contents_deep_free((zone_contents_t *)contents); +} + void zonedb_reload(conf_t *conf, server_t *server, reload_t mode) { if (conf == NULL || server == NULL) { @@ -625,7 +631,7 @@ void zonedb_reload(conf_t *conf, server_t *server, reload_t mode) /* Wait for readers to finish reading old zone database. */ synchronize_rcu(); - ptrlist_free_custom(&contents_tofree, NULL, (ptrlist_free_cb)zone_contents_deep_free); + ptrlist_free_custom(&contents_tofree, NULL, zone_contents_deep_free_wrap); /* Remove old zone DB. */ remove_old_zonedb(conf, db_old, server, mode); diff --git a/src/knot/zone/zonedb.c b/src/knot/zone/zonedb.c index 98cade5..b0388c7 100644 --- a/src/knot/zone/zonedb.c +++ b/src/knot/zone/zonedb.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -153,7 +153,7 @@ zone_t *knot_zonedb_find_suffix(knot_zonedb_t *db, const knot_dname_t *zone_name return NULL; } - zone_name = knot_wire_next_label(zone_name, NULL); + zone_name = knot_dname_next_label(zone_name); } } diff --git a/src/knot/zone/zonefile.c b/src/knot/zone/zonefile.c index ed075b6..9d0bf97 100644 --- a/src/knot/zone/zonefile.c +++ b/src/knot/zone/zonefile.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -81,12 +81,6 @@ int zcreator_step(zcreator_t *zc, const knot_rrset_t *rr) return KNOT_EINVAL; } - if (rr->type == KNOT_RRTYPE_SOA && - node_rrtype_exists(zc->z->apex, KNOT_RRTYPE_SOA)) { - // Ignore extra SOA - return KNOT_EOK; - } - zone_node_t *node = NULL; int ret = zone_contents_add_rr(zc->z, rr, &node); if (ret != KNOT_EOK) { @@ -219,10 +213,11 @@ zone_contents_t *zonefile_load(zloader_t *loader) goto fail; } - if (!node_rrtype_exists(loader->creator->z->apex, KNOT_RRTYPE_SOA)) { + knot_rdataset_t *soa = node_rdataset(zc->z->apex, KNOT_RRTYPE_SOA); + if (soa == NULL || soa->count != 1) { + sem_error_t code = (soa == NULL) ? SEM_ERR_SOA_NONE : SEM_ERR_SOA_MULTIPLE; loader->err_handler->error = true; - loader->err_handler->cb(loader->err_handler, zc->z, NULL, - SEM_ERR_SOA_NONE, NULL); + loader->err_handler->cb(loader->err_handler, zc->z, NULL, code, NULL); goto fail; } diff --git a/src/libdnssec/key/algorithm.c b/src/libdnssec/key/algorithm.c index a9bc3ee..d242442 100644 --- a/src/libdnssec/key/algorithm.c +++ b/src/libdnssec/key/algorithm.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -93,11 +93,9 @@ gnutls_pk_algorithm_t algorithm_to_gnutls(dnssec_key_algorithm_t dnssec) return GNUTLS_PK_RSA; case DNSSEC_KEY_ALGORITHM_ECDSA_P256_SHA256: case DNSSEC_KEY_ALGORITHM_ECDSA_P384_SHA384: - return GNUTLS_PK_EC; -#ifdef HAVE_ED25519 + return GNUTLS_PK_ECDSA; case DNSSEC_KEY_ALGORITHM_ED25519: return GNUTLS_PK_EDDSA_ED25519; -#endif #ifdef HAVE_ED448 case DNSSEC_KEY_ALGORITHM_ED448: return GNUTLS_PK_EDDSA_ED448; @@ -119,11 +117,7 @@ bool dnssec_algorithm_reproducible(dnssec_key_algorithm_t algorithm, bool enable return true; // those are always reproducible case DNSSEC_KEY_ALGORITHM_ECDSA_P256_SHA256: case DNSSEC_KEY_ALGORITHM_ECDSA_P384_SHA384: -#ifdef HAVE_GNUTLS_REPRODUCIBLE - return enabled; // Reproducible only if GnuTLS supports && enabled -#else - return false; -#endif + return enabled; // reproducible only if GnuTLS supports && enabled default: return false; } diff --git a/src/libdnssec/key/convert.c b/src/libdnssec/key/convert.c index 56168f7..d06c25e 100644 --- a/src/libdnssec/key/convert.c +++ b/src/libdnssec/key/convert.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -104,20 +104,16 @@ static size_t ecdsa_curve_point_size(gnutls_ecc_curve_t curve) } } -#if defined(HAVE_ED25519) || defined(HAVE_ED448) static size_t eddsa_curve_point_size(gnutls_ecc_curve_t curve) { switch (curve) { -#ifdef HAVE_ED25519 case GNUTLS_ECC_CURVE_ED25519: return 32; -#endif #ifdef HAVE_ED448 case GNUTLS_ECC_CURVE_ED448: return 57; #endif default: return 0; } } -#endif /*! * Convert ECDSA public key to DNSSEC format. @@ -157,7 +153,6 @@ static int ecdsa_pubkey_to_rdata(gnutls_pubkey_t key, dnssec_binary_t *rdata) /*! * Convert EDDSA public key to DNSSEC format. */ -#if defined(HAVE_ED25519) || defined(HAVE_ED448) static int eddsa_pubkey_to_rdata(gnutls_pubkey_t key, dnssec_binary_t *rdata) { assert(key); @@ -187,7 +182,6 @@ static int eddsa_pubkey_to_rdata(gnutls_pubkey_t key, dnssec_binary_t *rdata) return DNSSEC_EOK; } -#endif /* -- crypto to DNSSEC ------------------------------------------------------*/ @@ -248,20 +242,16 @@ static gnutls_ecc_curve_t ecdsa_curve_from_rdata_size(size_t rdata_size) /*! * Get EDDSA curve based on DNSKEY RDATA size. */ -#if defined(HAVE_ED25519) || defined(HAVE_ED448) static gnutls_ecc_curve_t eddsa_curve_from_rdata_size(size_t rdata_size) { switch (rdata_size) { -#ifdef HAVE_ED25519 case 32: return GNUTLS_ECC_CURVE_ED25519; -#endif #ifdef HAVE_ED448 case 57: return GNUTLS_ECC_CURVE_ED448; #endif default: return GNUTLS_ECC_CURVE_INVALID; } } -#endif /*! * Convert ECDSA key in DNSSEC format to crypto key. @@ -296,7 +286,6 @@ static int ecdsa_rdata_to_pubkey(const dnssec_binary_t *rdata, gnutls_pubkey_t k /*! * Convert EDDSA key in DNSSEC format to crypto key. */ -#if defined(HAVE_ED25519) || defined(HAVE_ED448) static int eddsa_rdata_to_pubkey(const dnssec_binary_t *rdata, gnutls_pubkey_t key) { assert(rdata); @@ -320,7 +309,6 @@ static int eddsa_rdata_to_pubkey(const dnssec_binary_t *rdata, gnutls_pubkey_t k return DNSSEC_EOK; } -#endif /* -- internal API --------------------------------------------------------- */ @@ -339,10 +327,8 @@ int convert_pubkey_to_dnskey(gnutls_pubkey_t key, dnssec_binary_t *rdata) switch ((gnutls_pk_algorithm_t)algorithm) { case GNUTLS_PK_RSA: return rsa_pubkey_to_rdata(key, rdata); - case GNUTLS_PK_EC: return ecdsa_pubkey_to_rdata(key, rdata); -#ifdef HAVE_ED25519 + case GNUTLS_PK_ECDSA: return ecdsa_pubkey_to_rdata(key, rdata); case GNUTLS_PK_EDDSA_ED25519: return eddsa_pubkey_to_rdata(key, rdata); -#endif #ifdef HAVE_ED448 case GNUTLS_PK_EDDSA_ED448: return eddsa_pubkey_to_rdata(key, rdata); #endif @@ -363,10 +349,8 @@ int convert_dnskey_to_pubkey(uint8_t algorithm, const dnssec_binary_t *rdata, switch(gnutls_alg) { case GNUTLS_PK_RSA: return rsa_rdata_to_pubkey(rdata, key); - case GNUTLS_PK_EC: return ecdsa_rdata_to_pubkey(rdata, key); -#ifdef HAVE_ED25519 + case GNUTLS_PK_ECDSA: return ecdsa_rdata_to_pubkey(rdata, key); case GNUTLS_PK_EDDSA_ED25519: return eddsa_rdata_to_pubkey(rdata, key); -#endif #ifdef HAVE_ED448 case GNUTLS_PK_EDDSA_ED448: return eddsa_rdata_to_pubkey(rdata, key); #endif diff --git a/src/libdnssec/pem.c b/src/libdnssec/pem.c index fa463f6..41fd855 100644 --- a/src/libdnssec/pem.c +++ b/src/libdnssec/pem.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -130,29 +130,10 @@ int dnssec_pem_from_x509(gnutls_x509_privkey_t key, dnssec_binary_t *pem) static int privkey_export_x509(gnutls_privkey_t key, gnutls_x509_privkey_t *_key) { -#ifdef HAVE_EXPORT_X509 if (gnutls_privkey_export_x509(key, _key) != GNUTLS_E_SUCCESS) { return DNSSEC_KEY_EXPORT_ERROR; } -#else // Needed for GnuTLS < 3.4.0 (CentOS 7) - struct privkey { // Extracted needed items only! - gnutls_privkey_type_t type; - gnutls_pk_algorithm_t pk_algorithm; - gnutls_x509_privkey_t x509; - }; - struct privkey *pkey = (struct privkey *)key; - assert(pkey->type == GNUTLS_PRIVKEY_X509); - - if (gnutls_x509_privkey_init(_key) != GNUTLS_E_SUCCESS) { - return DNSSEC_KEY_EXPORT_ERROR; - } - - if (gnutls_x509_privkey_cpy(*_key, pkey->x509) != GNUTLS_E_SUCCESS) { - gnutls_x509_privkey_deinit(*_key); - return DNSSEC_KEY_EXPORT_ERROR; - } -#endif return DNSSEC_EOK; } diff --git a/src/libdnssec/sign/sign.c b/src/libdnssec/sign/sign.c index 3a7bcba..727f650 100644 --- a/src/libdnssec/sign/sign.c +++ b/src/libdnssec/sign/sign.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -202,34 +202,6 @@ static const algorithm_functions_t *get_functions(const dnssec_key_t *key) } } -#ifndef HAVE_SIGN_DATA2 -/*! - * Get digest algorithm used with a given key. - */ -static gnutls_digest_algorithm_t get_digest_algorithm(const dnssec_key_t *key) -{ - uint8_t algorithm = dnssec_key_get_algorithm(key); - - switch ((dnssec_key_algorithm_t)algorithm) { - case DNSSEC_KEY_ALGORITHM_RSA_SHA1: - case DNSSEC_KEY_ALGORITHM_RSA_SHA1_NSEC3: - return GNUTLS_DIG_SHA1; - case DNSSEC_KEY_ALGORITHM_RSA_SHA256: - case DNSSEC_KEY_ALGORITHM_ECDSA_P256_SHA256: - return GNUTLS_DIG_SHA256; - case DNSSEC_KEY_ALGORITHM_RSA_SHA512: - return GNUTLS_DIG_SHA512; - case DNSSEC_KEY_ALGORITHM_ECDSA_P384_SHA384: - return GNUTLS_DIG_SHA384; - case DNSSEC_KEY_ALGORITHM_ED25519: - case DNSSEC_KEY_ALGORITHM_ED448: - return GNUTLS_DIG_SHA512; - default: - return GNUTLS_DIG_UNKNOWN; - } -} -#endif - static gnutls_sign_algorithm_t algo_dnssec2gnutls(dnssec_key_algorithm_t algorithm) { switch (algorithm) { @@ -244,10 +216,8 @@ static gnutls_sign_algorithm_t algo_dnssec2gnutls(dnssec_key_algorithm_t algorit return GNUTLS_SIGN_RSA_SHA512; case DNSSEC_KEY_ALGORITHM_ECDSA_P384_SHA384: return GNUTLS_SIGN_ECDSA_SHA384; -#ifdef HAVE_ED25519 case DNSSEC_KEY_ALGORITHM_ED25519: return GNUTLS_SIGN_EDDSA_ED25519; -#endif #ifdef HAVE_ED448 case DNSSEC_KEY_ALGORITHM_ED448: return GNUTLS_SIGN_EDDSA_ED448; @@ -356,24 +326,15 @@ int dnssec_sign_write(dnssec_sign_ctx_t *ctx, dnssec_sign_flags_t flags, dnssec_ }; unsigned gnutls_flags = 0; -#ifdef HAVE_GNUTLS_REPRODUCIBLE if (flags & DNSSEC_SIGN_REPRODUCIBLE) { gnutls_flags |= GNUTLS_PRIVKEY_FLAG_REPRODUCIBLE; } -#endif assert(ctx->key->private_key); _cleanup_datum_ gnutls_datum_t raw = { 0 }; -#ifdef HAVE_SIGN_DATA2 int result = gnutls_privkey_sign_data2(ctx->key->private_key, ctx->sign_algorithm, gnutls_flags, &data, &raw); -#else - gnutls_digest_algorithm_t digest_algorithm = get_digest_algorithm(ctx->key); - int result = gnutls_privkey_sign_data(ctx->key->private_key, - digest_algorithm, - gnutls_flags, &data, &raw); -#endif if (result < 0) { return DNSSEC_SIGN_ERROR; } diff --git a/src/libdnssec/version.h b/src/libdnssec/version.h index e72e2bd..cd5bad2 100644 --- a/src/libdnssec/version.h +++ b/src/libdnssec/version.h @@ -17,8 +17,8 @@ #pragma once #define DNSSEC_VERSION_MAJOR 3 -#define DNSSEC_VERSION_MINOR 3 -#define DNSSEC_VERSION_PATCH 0x09 +#define DNSSEC_VERSION_MINOR 4 +#define DNSSEC_VERSION_PATCH 0x00 #define DNSSEC_VERSION_HEX ((DNSSEC_VERSION_MAJOR << 16) | \ (DNSSEC_VERSION_MINOR << 8) | \ diff --git a/src/libknot/Makefile.inc b/src/libknot/Makefile.inc index f62d836..d09ff55 100755 --- a/src/libknot/Makefile.inc +++ b/src/libknot/Makefile.inc @@ -37,6 +37,8 @@ nobase_include_libknot_HEADERS = \ libknot/packet/wire.h \ libknot/probe/data.h \ libknot/probe/probe.h \ + libknot/quic/tls.h \ + libknot/quic/tls_common.h \ libknot/rdata.h \ libknot/rdataset.h \ libknot/rrset-dump.h \ @@ -78,6 +80,8 @@ libknot_la_SOURCES = \ libknot/packet/rrset-wire.c \ libknot/probe/data.c \ libknot/probe/probe.c \ + libknot/quic/tls.c \ + libknot/quic/tls_common.c \ libknot/rdataset.c \ libknot/rrset-dump.c \ libknot/rrset.c \ diff --git a/src/libknot/attribute.h b/src/libknot/attribute.h index 525aef3..ce464fc 100644 --- a/src/libknot/attribute.h +++ b/src/libknot/attribute.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -35,17 +35,19 @@ /*! \brief GNU C function attributes. */ #if __GNUC__ >= 3 -#define _pure_ __attribute__ ((pure)) -#define _const_ __attribute__ ((const)) -#define _noreturn_ __attribute__ ((noreturn)) -#define _malloc_ __attribute__ ((malloc)) -#define _mustcheck_ __attribute__ ((warn_unused_result)) +#define _pure_ __attribute__ ((pure)) +#define _const_ __attribute__ ((const)) +#define _noreturn_ __attribute__ ((noreturn)) +#define _malloc_ __attribute__ ((malloc)) +#define _mustcheck_ __attribute__ ((warn_unused_result)) +#define _nonnull_(...) __attribute__ ((nonnull(__VA_ARGS__))) #else #define _pure_ #define _const_ #define _noreturn_ #define _malloc_ #define _mustcheck_ +#define _nonnull_ #endif /*! @} */ diff --git a/src/libknot/control/control.c b/src/libknot/control/control.c index 671896f..8cddd5d 100644 --- a/src/libknot/control/control.c +++ b/src/libknot/control/control.c @@ -36,9 +36,6 @@ #define CTL_BUFF_SIZE (256 * 1024) #endif -/*! Listen backlog size. */ -#define DEFAULT_LISTEN_BACKLOG 5 - /*! Default socket operations timeout in milliseconds. */ #define DEFAULT_TIMEOUT (30 * 1000) @@ -166,6 +163,18 @@ knot_ctl_t* knot_ctl_alloc(void) } _public_ +knot_ctl_t* knot_ctl_clone(knot_ctl_t *ctx) +{ + knot_ctl_t *res = knot_ctl_alloc(); + if (res != NULL) { + res->timeout = ctx->timeout; + res->sock = ctx->sock; + ctx->sock = -1; + } + return res; +} + +_public_ void knot_ctl_free(knot_ctl_t *ctx) { if (ctx == NULL) { @@ -194,13 +203,7 @@ void knot_ctl_set_timeout(knot_ctl_t *ctx, int timeout_ms) } _public_ -int knot_ctl_bind(knot_ctl_t *ctx, const char *path) -{ - return knot_ctl_bind2(ctx, path, DEFAULT_LISTEN_BACKLOG); -} - -_public_ -int knot_ctl_bind2(knot_ctl_t *ctx, const char *path, unsigned backlog) +int knot_ctl_bind(knot_ctl_t *ctx, const char *path, unsigned backlog) { if (ctx == NULL || path == NULL) { return KNOT_EINVAL; diff --git a/src/libknot/control/control.h b/src/libknot/control/control.h index 8ab1e10..f110e3f 100644 --- a/src/libknot/control/control.h +++ b/src/libknot/control/control.h @@ -65,6 +65,18 @@ typedef struct knot_ctl knot_ctl_t; knot_ctl_t* knot_ctl_alloc(void); /*! + * \brief Allocates a control context based on an existing one. + * + * \param[in,out] ctx Original control context. + * + * \note The listen_sock is kept at the original, the current sock is taken + * by the clone and RESET in the original! + * + * \return Control context or NULL. + */ +knot_ctl_t* knot_ctl_clone(knot_ctl_t *ctx); + +/*! * Deallocates a control context. * * \param[in] ctx Control context. @@ -86,17 +98,13 @@ void knot_ctl_set_timeout(knot_ctl_t *ctx, int timeout_ms); * * \note Server operation. * - * \param[in] ctx Control context. - * \param[in] path Control UNIX socket path. + * \param[in] ctx Control context. + * \param[in] path Control UNIX socket path. + * \param[in] backlog Socket listen backlog size. * * \return Error code, KNOT_EOK if successful. */ -int knot_ctl_bind(knot_ctl_t *ctx, const char *path); - -/*! - * Same as knot_ctl_bind() with socket backlog specification. - */ -int knot_ctl_bind2(knot_ctl_t *ctx, const char *path, unsigned backlog); +int knot_ctl_bind(knot_ctl_t *ctx, const char *path, unsigned backlog); /*! * Unbinds a control socket. diff --git a/src/libknot/dname.c b/src/libknot/dname.c index 31b8a5f..d166f8d 100644 --- a/src/libknot/dname.c +++ b/src/libknot/dname.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -62,11 +62,11 @@ static int dname_align(const uint8_t **d1, uint8_t d1_labels, assert(d1 && d2); for (unsigned j = d1_labels; j < d2_labels; ++j) { - *d2 = knot_wire_next_label(*d2, NULL); + *d2 = knot_dname_next_label(*d2); } for (unsigned j = d2_labels; j < d1_labels; ++j) { - *d1 = knot_wire_next_label(*d1, NULL); + *d1 = knot_dname_next_label(*d1); } return (d1_labels < d2_labels) ? d1_labels : d2_labels; @@ -190,7 +190,7 @@ _public_ int knot_dname_unpack(uint8_t *dst, const knot_dname_t *src, size_t maxlen, const uint8_t *pkt) { - if (dst == NULL || src == NULL) { + if (dst == NULL || src == NULL || pkt == NULL) { return KNOT_EINVAL; } @@ -533,7 +533,7 @@ size_t knot_dname_size(const knot_dname_t *name) _public_ size_t knot_dname_realsize(const knot_dname_t *name, const uint8_t *pkt) { - if (name == NULL) { + if (name == NULL || pkt == NULL) { return 0; } @@ -573,8 +573,8 @@ size_t knot_dname_matched_labels(const knot_dname_t *d1, const knot_dname_t *d2) } /* Next label. */ - d1 = knot_wire_next_label(d1, NULL); - d2 = knot_wire_next_label(d2, NULL); + d1 = knot_dname_next_label(d1); + d2 = knot_dname_next_label(d2); --common; } @@ -596,7 +596,7 @@ knot_dname_t *knot_dname_replace_suffix(const knot_dname_t *name, unsigned label } size_t prefix_lbs = dname_lbs - labels; - size_t prefix_len = knot_dname_prefixlen(name, prefix_lbs, NULL); + size_t prefix_len = knot_dname_prefixlen(name, prefix_lbs); size_t suffix_len = knot_dname_size(suffix); if (prefix_len == 0 || suffix_len == 0) { return NULL; @@ -614,7 +614,7 @@ knot_dname_t *knot_dname_replace_suffix(const knot_dname_t *name, unsigned label while (prefix_lbs > 0) { memcpy(dst, name, *name + 1); dst += *name + 1; - name = knot_wire_next_label(name, NULL); + name = knot_dname_next_label(name); --prefix_lbs; } @@ -622,7 +622,7 @@ knot_dname_t *knot_dname_replace_suffix(const knot_dname_t *name, unsigned label while (*suffix != '\0') { memcpy(dst, suffix, *suffix + 1); dst += *suffix + 1; - suffix = knot_wire_next_label(suffix, NULL); + suffix = knot_dname_next_label(suffix); } *dst = '\0'; @@ -684,8 +684,8 @@ inline static bool dname_is_equal(const knot_dname_t *d1, const knot_dname_t *d2 while (*d1 != '\0' || *d2 != '\0') { if (label_is_equal(d1, d2, no_case)) { - d1 = knot_wire_next_label(d1, NULL); - d2 = knot_wire_next_label(d2, NULL); + d1 = knot_dname_next_label(d1); + d2 = knot_dname_next_label(d2); } else { return false; } @@ -707,7 +707,7 @@ bool knot_dname_is_case_equal(const knot_dname_t *d1, const knot_dname_t *d2) } _public_ -size_t knot_dname_prefixlen(const uint8_t *name, unsigned nlabels, const uint8_t *pkt) +size_t knot_dname_prefixlen(const uint8_t *name, unsigned nlabels) { if (name == NULL) { return 0; @@ -718,13 +718,10 @@ size_t knot_dname_prefixlen(const uint8_t *name, unsigned nlabels, const uint8_t return 0; } - /* Seek first real label occurrence. */ - name = knot_wire_seek_label(name, pkt); - size_t len = 0; while (*name != '\0') { len += *name + 1; - name = knot_wire_next_label(name, pkt); + name = knot_dname_next_label(name); if (--nlabels == 0) { /* Count N first labels only. */ break; } @@ -743,7 +740,8 @@ size_t knot_dname_labels(const uint8_t *name, const uint8_t *pkt) size_t count = 0; while (*name != '\0') { ++count; - name = knot_wire_next_label(name, pkt); + name = (pkt == NULL) ? knot_dname_next_label(name) : + knot_wire_next_label(name, pkt); if (name == NULL) { return 0; } @@ -794,7 +792,7 @@ int knot_dname_in_bailiwick(const knot_dname_t *name, const knot_dname_t *bailiw } for (int i = 0; i < label_diff; ++i) { - name = knot_wire_next_label(name, NULL); + name = knot_dname_next_label(name); } return knot_dname_is_equal(name, bailiwick) ? label_diff : KNOT_EOUTOFZONE; diff --git a/src/libknot/dname.h b/src/libknot/dname.h index 5733de9..6d72f90 100644 --- a/src/libknot/dname.h +++ b/src/libknot/dname.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -48,7 +48,7 @@ typedef char knot_dname_txt_storage_t[KNOT_DNAME_TXT_MAXLEN + 1]; * * \param name Name on the wire. * \param endp Name boundary. - * \param pkt Wire. + * \param pkt Wire (can be NULL if not compressed). * * \retval (compressed) size of the domain name. * \retval KNOT_EINVAL @@ -195,7 +195,7 @@ size_t knot_dname_size(const knot_dname_t *name); * \brief Returns full size of the given domain name (expanded compression ptrs). * * \param name Domain name to get the size of. - * \param pkt Related packet (or NULL if unpacked) + * \param pkt Related packet. * * \retval size of the domain name. * \retval 0 if invalid argument. @@ -295,12 +295,11 @@ bool knot_dname_is_case_equal(const knot_dname_t *d1, const knot_dname_t *d2); * * \param name Domain name. * \param nlabels First N labels. - * \param pkt Related packet (or NULL if not compressed). * * \return Length of the prefix. */ _pure_ -size_t knot_dname_prefixlen(const uint8_t *name, unsigned nlabels, const uint8_t *pkt); +size_t knot_dname_prefixlen(const uint8_t *name, unsigned nlabels); /*! * \brief Return number of labels in the domain name. diff --git a/src/libknot/errcode.h b/src/libknot/errcode.h index 6ec4a94..3ee326c 100644 --- a/src/libknot/errcode.h +++ b/src/libknot/errcode.h @@ -110,6 +110,7 @@ enum knot_error { KNOT_EBADCERTKEY, KNOT_EFACCES, KNOT_EBACKUPDATA, + KNOT_ECPUCOMPAT, KNOT_GENERAL_ERROR = -900, @@ -121,6 +122,7 @@ enum knot_error { KNOT_NET_EADDR, KNOT_NET_ESOCKET, KNOT_NET_ECONNECT, + KNOT_NET_EHSHAKE, KNOT_NET_ESEND, KNOT_NET_ERECV, KNOT_NET_ETIMEOUT, @@ -176,6 +178,7 @@ enum knot_error { KNOT_NO_PUBLIC_KEY, KNOT_NO_PRIVATE_KEY, KNOT_NO_READY_KEY, + KNOT_ESOON_EXPIRE, KNOT_DNSSEC_EKEYTAG_LIMIT, KNOT_DNSSEC_EXTRA_NSEC, diff --git a/src/libknot/error.c b/src/libknot/error.c index ae9b973..59f0a7a 100644 --- a/src/libknot/error.c +++ b/src/libknot/error.c @@ -109,6 +109,7 @@ static const struct error errors[] = { { KNOT_EBADCERTKEY, "unknown certificate key" }, { KNOT_EFACCES, "file permission denied" }, { KNOT_EBACKUPDATA, "requested data not in backup" }, + { KNOT_ECPUCOMPAT, "incompatible CPU architecture" }, { KNOT_GENERAL_ERROR, "unknown general error" }, @@ -120,6 +121,7 @@ static const struct error errors[] = { { KNOT_NET_EADDR, "bad address or host name" }, { KNOT_NET_ESOCKET, "can't create socket" }, { KNOT_NET_ECONNECT, "can't connect" }, + { KNOT_NET_EHSHAKE, "handshake failed" }, { KNOT_NET_ESEND, "can't send data" }, { KNOT_NET_ERECV, "can't receive data" }, { KNOT_NET_ETIMEOUT, "network timeout" }, @@ -175,6 +177,7 @@ static const struct error errors[] = { { KNOT_NO_PUBLIC_KEY, "no public key" }, { KNOT_NO_PRIVATE_KEY, "no private key" }, { KNOT_NO_READY_KEY, "no key ready for submission" }, + { KNOT_ESOON_EXPIRE, "oncoming RRSIG expiration" }, { KNOT_DNSSEC_EKEYTAG_LIMIT, "many keys with equal keytag" }, { KNOT_DNSSEC_EXTRA_NSEC, "superfluous NSEC(3)" }, diff --git a/src/libknot/packet/pkt.h b/src/libknot/packet/pkt.h index 383f55e..da69c8c 100644 --- a/src/libknot/packet/pkt.h +++ b/src/libknot/packet/pkt.h @@ -52,7 +52,6 @@ enum { KNOT_PF_NOCANON = 1 << 5, /*!< Don't canonicalize rrsets during parsing. */ KNOT_PF_ORIGTTL = 1 << 6, /*!< Write RRSIGs with their original TTL. */ KNOT_PF_SOAMINTTL = 1 << 7, /*!< Write SOA with its minimum-ttl as TTL. */ - KNOT_PF_BUFENOUGH = 1 << 8, /*!< The output buffer is big enough for the output. */ }; typedef struct knot_pkt knot_pkt_t; diff --git a/src/libknot/packet/rrset-wire.c b/src/libknot/packet/rrset-wire.c index ef3a068..1d4f78e 100644 --- a/src/libknot/packet/rrset-wire.c +++ b/src/libknot/packet/rrset-wire.c @@ -73,6 +73,7 @@ static bool dname_equal_wire(const knot_dname_t *d1, const knot_dname_t *d2, { assert(d1); assert(d2); + assert(wire); d2 = knot_wire_seek_label(d2, wire); @@ -80,7 +81,7 @@ static bool dname_equal_wire(const knot_dname_t *d1, const knot_dname_t *d2, if (!label_is_equal(d1, d2)) { return false; } - d1 = knot_wire_next_label(d1, NULL); + d1 = knot_dname_next_label(d1); d2 = knot_wire_next_label(d2, wire); } @@ -170,7 +171,7 @@ static int write_rdata_naptr_header(const uint8_t **src, size_t *src_avail, written += (len); \ } -#define CHECK_NEXT_LABEL(res) \ +#define CHECK_WIRE_NEXT_LABEL(res) \ if (res == NULL) { return KNOT_EINVAL; } /*! @@ -201,7 +202,7 @@ static int compr_put_dname(const knot_dname_t *dname, uint8_t *dst, uint16_t max int suffix_labels = compr->suffix.labels; while (suffix_labels > name_labels) { suffix = knot_wire_next_label(suffix, compr->wire); - CHECK_NEXT_LABEL(suffix); + CHECK_WIRE_NEXT_LABEL(suffix); --suffix_labels; } @@ -210,8 +211,7 @@ static int compr_put_dname(const knot_dname_t *dname, uint8_t *dst, uint16_t max uint16_t written = 0; while (name_labels > suffix_labels) { WRITE_LABEL(dst, written, dname, max, (*dname + 1)); - dname = knot_wire_next_label(dname, NULL); - CHECK_NEXT_LABEL(dname); + dname = knot_dname_next_label(dname); --name_labels; } @@ -221,10 +221,9 @@ static int compr_put_dname(const knot_dname_t *dname, uint8_t *dst, uint16_t max const knot_dname_t *compr_ptr = suffix; while (dname[0] != '\0') { // Next labels. - const knot_dname_t *next_dname = knot_wire_next_label(dname, NULL); - CHECK_NEXT_LABEL(next_dname); + const knot_dname_t *next_dname = knot_dname_next_label(dname); const knot_dname_t *next_suffix = knot_wire_next_label(suffix, compr->wire); - CHECK_NEXT_LABEL(next_suffix); + CHECK_WIRE_NEXT_LABEL(next_suffix); // Two labels match, extend suffix length. if (!label_is_equal(dname, suffix)) { @@ -495,7 +494,7 @@ static int write_rr(const knot_rrset_t *rrset, uint16_t rrset_index, _public_ int knot_rrset_to_wire_extra(const knot_rrset_t *rrset, uint8_t *wire, - uint16_t max_size, uint16_t rotate, + uint32_t max_size, uint16_t rotate, knot_compr_t *compr, uint16_t flags) { if (rrset == NULL || wire == NULL) { @@ -511,11 +510,6 @@ int knot_rrset_to_wire_extra(const knot_rrset_t *rrset, uint8_t *wire, uint8_t *write = wire; size_t capacity = max_size; - // FIXME remove this and make the max_size parameter uint32_t in next major libknot release! - if ((flags & KNOT_PF_BUFENOUGH)) { - capacity = SIZE_MAX; - } - uint16_t count = rrset->rrs.count; knot_rdata_t *rdata = rotate > 1 ? knot_rdataset_at(&rrset->rrs, rotate - 1) : rrset->rrs.rdata; for (int i = rotate; i < count + rotate; i++) { diff --git a/src/libknot/packet/rrset-wire.h b/src/libknot/packet/rrset-wire.h index 3be0cba..3247df8 100644 --- a/src/libknot/packet/rrset-wire.h +++ b/src/libknot/packet/rrset-wire.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -41,12 +41,12 @@ * \return Output size, negative number on error (KNOT_E*). */ int knot_rrset_to_wire_extra(const knot_rrset_t *rrset, uint8_t *wire, - uint16_t max_size, uint16_t rotate, + uint32_t max_size, uint16_t rotate, knot_compr_t *compr, uint16_t flags); /*! \brief Same as knot_rrset_to_wire_extra but without rrset rotation and flags. */ static inline int knot_rrset_to_wire(const knot_rrset_t *rrset, uint8_t *wire, - uint16_t max_size, knot_compr_t *compr) + uint32_t max_size, knot_compr_t *compr) { return knot_rrset_to_wire_extra(rrset, wire, max_size, 0, compr, 0); } diff --git a/src/libknot/packet/wire.h b/src/libknot/packet/wire.h index 630cd83..cff4b21 100644 --- a/src/libknot/packet/wire.h +++ b/src/libknot/packet/wire.h @@ -1025,13 +1025,11 @@ static inline uint16_t knot_wire_get_pointer(const uint8_t *pos) return (knot_wire_read_u16(pos) - KNOT_WIRE_PTR_BASE); // Return offset. } -_pure_ _mustcheck_ +_pure_ _mustcheck_ _nonnull_(2) static inline const uint8_t *knot_wire_seek_label(const uint8_t *lp, const uint8_t *wire) { + assert(wire); while (knot_wire_is_pointer(lp)) { - if (!wire) { - return NULL; - } const uint8_t *new_lp = wire + knot_wire_get_pointer(lp); if (new_lp >= lp) { assert(0); @@ -1042,12 +1040,21 @@ static inline const uint8_t *knot_wire_seek_label(const uint8_t *lp, const uint8 return lp; } -_pure_ _mustcheck_ +_pure_ _mustcheck_ _nonnull_(1, 2) static inline const uint8_t *knot_wire_next_label(const uint8_t *lp, const uint8_t *wire) { - if (!lp || !lp[0]) /* No label after final label. */ - return NULL; + assert(lp); + assert(lp[0] > 0); // Not a terminal label. return knot_wire_seek_label(lp + (lp[0] + sizeof(uint8_t)), wire); } +_pure_ _mustcheck_ _nonnull_(1) +static inline const uint8_t *knot_dname_next_label(const uint8_t *lp) +{ + assert(lp); + assert(lp[0] > 0); // Not a terminal label. + assert(!knot_wire_is_pointer(lp)); + return lp + (lp[0] + sizeof(uint8_t)); +} + /*! @} */ diff --git a/src/libknot/quic/quic.c b/src/libknot/quic/quic.c index f9d1d1d..4eb84c3 100644 --- a/src/libknot/quic/quic.c +++ b/src/libknot/quic/quic.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -33,7 +33,6 @@ #include "contrib/macros.h" #include "contrib/sockaddr.h" -#include "contrib/string.h" #include "contrib/ucw/lists.h" #include "libknot/endian.h" #include "libdnssec/error.h" @@ -58,19 +57,6 @@ #define TLS_CALLBACK_ERR (-1) -const gnutls_datum_t doq_alpn = { - (unsigned char *)"doq", 3 -}; - -typedef struct knot_quic_creds { - gnutls_certificate_credentials_t tls_cert; - gnutls_anti_replay_t tls_anti_replay; - gnutls_datum_t tls_ticket_key; - bool peer; - uint8_t peer_pin_len; - uint8_t peer_pin[]; -} knot_quic_creds_t; - typedef struct knot_quic_session { node_t n; gnutls_datum_t tls_session; @@ -153,223 +139,6 @@ session_free: return ret; } -static int tls_anti_replay_db_add_func(void *dbf, time_t exp_time, - const gnutls_datum_t *key, - const gnutls_datum_t *data) -{ - return 0; -} - -static void tls_session_ticket_key_free(gnutls_datum_t *ticket) -{ - gnutls_memset(ticket->data, 0, ticket->size); - gnutls_free(ticket->data); -} - -static int self_key(gnutls_x509_privkey_t *privkey, const char *key_file) -{ - gnutls_datum_t data = { 0 }; - - int ret = gnutls_x509_privkey_init(privkey); - if (ret != GNUTLS_E_SUCCESS) { - return ret; - } - - int fd = open(key_file, O_RDONLY); - if (fd != -1) { - struct stat stat; - if (fstat(fd, &stat) != 0 || - (data.data = gnutls_malloc(stat.st_size)) == NULL || - read(fd, data.data, stat.st_size) != stat.st_size) { - ret = GNUTLS_E_KEYFILE_ERROR; - goto finish; - } - - data.size = stat.st_size; - ret = gnutls_x509_privkey_import_pkcs8(*privkey, &data, GNUTLS_X509_FMT_PEM, - NULL, GNUTLS_PKCS_PLAIN); - if (ret != GNUTLS_E_SUCCESS) { - goto finish; - } - } else { - ret = gnutls_x509_privkey_generate(*privkey, GNUTLS_PK_EDDSA_ED25519, - GNUTLS_CURVE_TO_BITS(GNUTLS_ECC_CURVE_ED25519), 0); - if (ret != GNUTLS_E_SUCCESS) { - goto finish; - } - - ret = gnutls_x509_privkey_export2_pkcs8(*privkey, GNUTLS_X509_FMT_PEM, NULL, - GNUTLS_PKCS_PLAIN, &data); - if (ret != GNUTLS_E_SUCCESS || - (fd = open(key_file, O_WRONLY | O_CREAT, 0600)) == -1 || - write(fd, data.data, data.size) != data.size) { - ret = GNUTLS_E_KEYFILE_ERROR; - goto finish; - } - } - -finish: - close(fd); - gnutls_free(data.data); - if (ret != GNUTLS_E_SUCCESS) { - gnutls_x509_privkey_deinit(*privkey); - *privkey = NULL; - } - return ret; -} - -static int self_signed_cert(gnutls_certificate_credentials_t tls_cert, - const char *key_file) -{ - gnutls_x509_privkey_t privkey = NULL; - gnutls_x509_crt_t cert = NULL; - - char *hostname = sockaddr_hostname(); - if (hostname == NULL) { - return GNUTLS_E_MEMORY_ERROR; - } - - int ret; - uint8_t serial[16]; - gnutls_rnd(GNUTLS_RND_NONCE, serial, sizeof(serial)); - // Clear the left-most bit to be a positive number (two's complement form). - serial[0] &= 0x7F; - -#define CHK(cmd) if ((ret = (cmd)) != GNUTLS_E_SUCCESS) { goto finish; } -#define NOW_DAYS(days) (time(NULL) + 24 * 3600 * (days)) - - CHK(self_key(&privkey, key_file)); - - CHK(gnutls_x509_crt_init(&cert)); - CHK(gnutls_x509_crt_set_version(cert, 3)); - CHK(gnutls_x509_crt_set_serial(cert, serial, sizeof(serial))); - CHK(gnutls_x509_crt_set_activation_time(cert, NOW_DAYS(-1))); - CHK(gnutls_x509_crt_set_expiration_time(cert, NOW_DAYS(10 * 365))); - CHK(gnutls_x509_crt_set_dn_by_oid(cert, GNUTLS_OID_X520_COMMON_NAME, 0, - hostname, strlen(hostname))); - CHK(gnutls_x509_crt_set_key(cert, privkey)); - CHK(gnutls_x509_crt_sign2(cert, cert, privkey, GNUTLS_DIG_SHA512, 0)); - - ret = gnutls_certificate_set_x509_key(tls_cert, &cert, 1, privkey); - -finish: - free(hostname); - gnutls_x509_crt_deinit(cert); - gnutls_x509_privkey_deinit(privkey); - - return ret; -} - -_public_ -struct knot_quic_creds *knot_quic_init_creds(const char *cert_file, - const char *key_file) -{ - knot_quic_creds_t *creds = calloc(1, sizeof(*creds)); - if (creds == NULL) { - return NULL; - } - - int ret = gnutls_certificate_allocate_credentials(&creds->tls_cert); - if (ret != GNUTLS_E_SUCCESS) { - goto fail; - } - - ret = gnutls_anti_replay_init(&creds->tls_anti_replay); - if (ret != GNUTLS_E_SUCCESS) { - goto fail; - } - gnutls_anti_replay_set_add_function(creds->tls_anti_replay, tls_anti_replay_db_add_func); - gnutls_anti_replay_set_ptr(creds->tls_anti_replay, NULL); - - if (cert_file != NULL) { - ret = gnutls_certificate_set_x509_key_file(creds->tls_cert, - cert_file, key_file, - GNUTLS_X509_FMT_PEM); - } else { - ret = self_signed_cert(creds->tls_cert, key_file); - } - if (ret != GNUTLS_E_SUCCESS) { - goto fail; - } - - ret = gnutls_session_ticket_key_generate(&creds->tls_ticket_key); - if (ret != GNUTLS_E_SUCCESS) { - goto fail; - } - - return creds; -fail: - knot_quic_free_creds(creds); - return NULL; -} - -_public_ -struct knot_quic_creds *knot_quic_init_creds_peer(const struct knot_quic_creds *local_creds, - const uint8_t *peer_pin, - uint8_t peer_pin_len) -{ - knot_quic_creds_t *creds = calloc(1, sizeof(*creds) + peer_pin_len); - if (creds == NULL) { - return NULL; - } - - if (local_creds != NULL) { - creds->peer = true; - creds->tls_cert = local_creds->tls_cert; - } else { - int ret = gnutls_certificate_allocate_credentials(&creds->tls_cert); - if (ret != GNUTLS_E_SUCCESS) { - free(creds); - return NULL; - } - } - - if (peer_pin_len > 0 && peer_pin != NULL) { - memcpy(creds->peer_pin, peer_pin, peer_pin_len); - creds->peer_pin_len = peer_pin_len; - } - - return creds; -} - -_public_ -int knot_quic_creds_cert(struct knot_quic_creds *creds, struct gnutls_x509_crt_int **cert) -{ - if (creds == NULL || cert == NULL) { - return KNOT_EINVAL; - } - - gnutls_x509_crt_t *certs; - unsigned cert_count; - int ret = gnutls_certificate_get_x509_crt(creds->tls_cert, 0, &certs, &cert_count); - if (ret == GNUTLS_E_SUCCESS) { - if (cert_count == 0) { - gnutls_x509_crt_deinit(*certs); - return KNOT_ENOENT; - } - *cert = *certs; - free(certs); - } - return ret; -} - -_public_ -void knot_quic_free_creds(struct knot_quic_creds *creds) -{ - if (creds == NULL) { - return; - } - - if (!creds->peer && creds->tls_cert != NULL) { - gnutls_certificate_free_credentials(creds->tls_cert); - } - gnutls_anti_replay_deinit(creds->tls_anti_replay); - if (creds->tls_ticket_key.data != NULL) { - tls_session_ticket_key_free(&creds->tls_ticket_key); - } - free(creds); -} - static ngtcp2_conn *get_conn(ngtcp2_crypto_conn_ref *conn_ref) { return ((knot_quic_conn_t *)conn_ref->user_data)->conn; @@ -377,51 +146,31 @@ static ngtcp2_conn *get_conn(ngtcp2_crypto_conn_ref *conn_ref) static int tls_init_conn_session(knot_quic_conn_t *conn, bool server) { - if (gnutls_init(&conn->tls_session, (server ? GNUTLS_SERVER : GNUTLS_CLIENT) | - GNUTLS_ENABLE_EARLY_DATA | GNUTLS_NO_AUTO_SEND_TICKET | - GNUTLS_NO_END_OF_EARLY_DATA) != GNUTLS_E_SUCCESS) { - return TLS_CALLBACK_ERR; - } - - gnutls_certificate_send_x509_rdn_sequence(conn->tls_session, 1); - gnutls_certificate_server_set_request(conn->tls_session, GNUTLS_CERT_REQUEST); - - if (gnutls_priority_set_direct(conn->tls_session, QUIC_PRIORITIES, - NULL) != GNUTLS_E_SUCCESS) { + int ret = knot_tls_session(&conn->tls_session, conn->quic_table->creds, + conn->quic_table->priority, "\x03""doq", + true, server); + if (ret != KNOT_EOK) { return TLS_CALLBACK_ERR; } - if (server && gnutls_session_ticket_enable_server(conn->tls_session, - &conn->quic_table->creds->tls_ticket_key) != GNUTLS_E_SUCCESS) { - return TLS_CALLBACK_ERR; + if (server) { + ret = ngtcp2_crypto_gnutls_configure_server_session(conn->tls_session); + } else { + ret = ngtcp2_crypto_gnutls_configure_client_session(conn->tls_session); } - - int ret = ngtcp2_crypto_gnutls_configure_server_session(conn->tls_session); - if (ret != 0) { + if (ret != NGTCP2_NO_ERROR) { return TLS_CALLBACK_ERR; } - gnutls_record_set_max_early_data_size(conn->tls_session, 0xffffffffu); - conn->conn_ref = (nc_conn_ref_placeholder_t) { .get_conn = get_conn, .user_data = conn }; - _Static_assert(sizeof(nc_conn_ref_placeholder_t) == sizeof(ngtcp2_crypto_conn_ref), "invalid placeholder for conn_ref"); + _Static_assert(sizeof(nc_conn_ref_placeholder_t) == sizeof(ngtcp2_crypto_conn_ref), + "invalid placeholder for conn_ref"); gnutls_session_set_ptr(conn->tls_session, &conn->conn_ref); - if (server) { - gnutls_anti_replay_enable(conn->tls_session, conn->quic_table->creds->tls_anti_replay); - - } - if (gnutls_credentials_set(conn->tls_session, GNUTLS_CRD_CERTIFICATE, - conn->quic_table->creds->tls_cert) != GNUTLS_E_SUCCESS) { - return TLS_CALLBACK_ERR; - } - - gnutls_alpn_set_protocols(conn->tls_session, &doq_alpn, 1, GNUTLS_ALPN_MANDATORY); - ngtcp2_conn_set_tls_native_handle(conn->conn, conn->tls_session); return KNOT_EOK; @@ -477,54 +226,6 @@ uint16_t knot_quic_conn_local_port(knot_quic_conn_t *conn) return ((const struct sockaddr_in6 *)path->local.addr)->sin6_port; } -_public_ -void knot_quic_conn_pin(knot_quic_conn_t *conn, uint8_t *pin, size_t *pin_size, bool local) -{ - if (conn == NULL) { - goto error; - } - - const gnutls_datum_t *data = NULL; - if (local) { - data = gnutls_certificate_get_ours(conn->tls_session); - } else { - unsigned count = 0; - data = gnutls_certificate_get_peers(conn->tls_session, &count); - if (count == 0) { - goto error; - } - } - if (data == NULL) { - goto error; - } - - gnutls_x509_crt_t cert; - int ret = gnutls_x509_crt_init(&cert); - if (ret != GNUTLS_E_SUCCESS) { - goto error; - } - - ret = gnutls_x509_crt_import(cert, data, GNUTLS_X509_FMT_DER); - if (ret != GNUTLS_E_SUCCESS) { - gnutls_x509_crt_deinit(cert); - goto error; - } - - ret = gnutls_x509_crt_get_key_id(cert, GNUTLS_KEYID_USE_SHA256, pin, pin_size); - if (ret != GNUTLS_E_SUCCESS) { - gnutls_x509_crt_deinit(cert); - goto error; - } - - gnutls_x509_crt_deinit(cert); - - return; -error: - if (pin_size != NULL) { - *pin_size = 0; - } -} - static void knot_quic_rand_cb(uint8_t *dest, size_t destlen, const ngtcp2_rand_ctx *rand_ctx) { (void)rand_ctx; @@ -602,18 +303,8 @@ static int handshake_completed_cb(ngtcp2_conn *conn, void *user_data) ctx->flags |= KNOT_QUIC_CONN_HANDSHAKE_DONE; if (!ngtcp2_conn_is_server(conn)) { - knot_quic_creds_t *creds = ctx->quic_table->creds; - if (creds->peer_pin_len == 0) { - return 0; - } - uint8_t pin[KNOT_QUIC_PIN_LEN]; - size_t pin_size = sizeof(pin); - knot_quic_conn_pin(ctx, pin, &pin_size, false); - if (pin_size != creds->peer_pin_len || - const_time_memcmp(pin, creds->peer_pin, pin_size) != 0) { - return NGTCP2_ERR_CALLBACK_FAILURE; - } - return 0; + return knot_tls_pin_check(ctx->tls_session, ctx->quic_table->creds) + == KNOT_EOK ? 0 : NGTCP2_ERR_CALLBACK_FAILURE; } if (gnutls_session_ticket_send(ctx->tls_session, 1, 0) != GNUTLS_E_SUCCESS) { @@ -945,6 +636,10 @@ int knot_quic_handle(knot_quic_table_t *table, knot_quic_reply_t *reply, goto finish; } + if (conn != NULL && (conn->flags & KNOT_QUIC_CONN_BLOCKED)) { + return KNOT_EOK; + } + ngtcp2_path path; path.remote.addr = (struct sockaddr *)reply->ip_rem; path.remote.addrlen = addr_len((struct sockaddr_in6 *)reply->ip_rem); @@ -1249,6 +944,8 @@ int knot_quic_send(knot_quic_table_t *quic_table, knot_quic_conn_t *conn, return KNOT_EINVAL; } else if (reply->handle_ret < 0) { return reply->handle_ret; + } else if ((conn->flags & KNOT_QUIC_CONN_BLOCKED) && !(flags & KNOT_QUIC_SEND_IGNORE_BLOCKED)) { + return KNOT_EOK; } else if (reply->handle_ret > 0) { return send_special(quic_table, reply, conn); } else if (conn == NULL) { diff --git a/src/libknot/quic/quic.h b/src/libknot/quic/quic.h index 29a02e0..b4acb33 100644 --- a/src/libknot/quic/quic.h +++ b/src/libknot/quic/quic.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -29,20 +29,18 @@ #include <netinet/in.h> #include "libknot/quic/quic_conn.h" - -#define KNOT_QUIC_PIN_LEN 32 +#include "libknot/quic/tls_common.h" #define KNOT_QUIC_HANDLE_RET_CLOSE 2000 // RFC 9250 #define KNOT_QUIC_ERR_EXCESSIVE_LOAD 0x4 -struct gnutls_x509_crt_int; -struct knot_quic_creds; struct knot_quic_session; typedef enum { KNOT_QUIC_SEND_IGNORE_LASTBYTE = (1 << 0), + KNOT_QUIC_SEND_IGNORE_BLOCKED = (1 << 1), } knot_quic_send_flag_t; typedef struct knot_quic_reply { @@ -87,45 +85,6 @@ struct knot_quic_session *knot_quic_session_save(knot_quic_conn_t *conn); int knot_quic_session_load(knot_quic_conn_t *conn, struct knot_quic_session *session); /*! - * \brief Init server TLS certificate for DoQ. - * - * \param cert_file X509 certificate PEM file path/name (NULL if auto-generated). - * \param key_file Key PEM file path/name. - * - * \return Initialized creds. - */ -struct knot_quic_creds *knot_quic_init_creds(const char *cert_file, - const char *key_file); - -/*! - * \brief Init peer TLS certificate for DoQ. - * - * \param local_creds Local credentials if server. - * \param peer_pin Optional peer certificate pin to check. - * \param peer_pin_len Length of the peer pin. Set 0 if not specified. - * - * \return Initialized creds. - */ -struct knot_quic_creds *knot_quic_init_creds_peer(const struct knot_quic_creds *local_creds, - const uint8_t *peer_pin, - uint8_t peer_pin_len); - -/*! - * \brief Gets the certificate from credentials. - * - * \param creds TLS credentials. - * \param cert Output certificate. - * - * \return KNOT_E* - */ -int knot_quic_creds_cert(struct knot_quic_creds *creds, struct gnutls_x509_crt_int **cert); - -/*! - * \brief Deinit server TLS certificate for DoQ. - */ -void knot_quic_free_creds(struct knot_quic_creds *creds); - -/*! * \brief Returns timeout value for the connection. */ uint64_t quic_conn_get_timeout(knot_quic_conn_t *conn); @@ -156,18 +115,6 @@ uint32_t knot_quic_conn_rtt(knot_quic_conn_t *conn); uint16_t knot_quic_conn_local_port(knot_quic_conn_t *conn); /*! - * \brief Gets local or remote certificate pin. - * - * \note Zero output pin_size value means no certificate available or error. - * - * \param conn QUIC connection. - * \param pin Output certificate pin. - * \param pin_size Input size of the storage / output size of the stored pin. - * \param local Local or remote certificate indication. - */ -void knot_quic_conn_pin(knot_quic_conn_t *conn, uint8_t *pin, size_t *pin_size, bool local); - -/*! * \brief Create new outgoing QUIC connection. * * \param table QUIC connections table to be added to. diff --git a/src/libknot/quic/quic_conn.c b/src/libknot/quic/quic_conn.c index 6616573..1a3b9df 100644 --- a/src/libknot/quic/quic_conn.c +++ b/src/libknot/quic/quic_conn.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -29,6 +29,7 @@ #include "libdnssec/random.h" #include "libknot/attribute.h" #include "libknot/error.h" +#include "libknot/quic/tls_common.h" #include "libknot/quic/quic.h" #include "libknot/xdp/tcp_iobuf.h" #include "libknot/wire.h" @@ -45,7 +46,7 @@ static int cmp_expiry_heap_nodes(void *c1, void *c2) _public_ knot_quic_table_t *knot_quic_table_new(size_t max_conns, size_t max_ibufs, size_t max_obufs, - size_t udp_payload, struct knot_quic_creds *creds) + size_t udp_payload, struct knot_creds *creds) { size_t table_size = max_conns * BUCKETS_PER_CONNS; @@ -61,9 +62,17 @@ knot_quic_table_t *knot_quic_table_new(size_t max_conns, size_t max_ibufs, size_ res->obufs_max = max_obufs; res->udp_payload_limit = udp_payload; + int ret = gnutls_priority_init2(&res->priority, KNOT_TLS_PRIORITIES, NULL, + GNUTLS_PRIORITY_INIT_DEF_APPEND); + if (ret != GNUTLS_E_SUCCESS) { + free(res); + return NULL; + } + res->expiry_heap = malloc(sizeof(struct heap)); if (res->expiry_heap == NULL || !heap_init(res->expiry_heap, cmp_expiry_heap_nodes, 0)) { free(res->expiry_heap); + gnutls_priority_deinit(res->priority); free(res); return NULL; } @@ -92,6 +101,7 @@ void knot_quic_table_free(knot_quic_table_t *table) assert(table->ibufs_size == 0); assert(table->obufs_size == 0); + gnutls_priority_deinit(table->priority); heap_deinit(table->expiry_heap); free(table->expiry_heap); free(table); @@ -118,7 +128,9 @@ void knot_quic_table_sweep(knot_quic_table_t *table, struct knot_quic_reply *swe while (!EMPTY_HEAP(table->expiry_heap)) { knot_quic_conn_t *c = *(knot_quic_conn_t **)HHEAD(table->expiry_heap); - if (table->usage > table->max_conns) { + if ((c->flags & KNOT_QUIC_CONN_BLOCKED)) { + break; // highly inprobable + } else if (table->usage > table->max_conns) { knot_sweep_stats_incr(stats, KNOT_SWEEP_CTR_LIMIT_CONN); send_excessive_load(c, sweep_reply, table); knot_quic_table_rem(c, table); @@ -476,7 +488,7 @@ uint8_t *knot_quic_stream_add_data(knot_quic_conn_t *conn, int64_t stream_id, add_tail((list_t *)&s->outbufs, (node_t *)obuf); s->obufs_size += obuf->len; conn->obufs_size += obuf->len; - conn->quic_table->obufs_size += obuf->len; + ATOMIC_ADD(conn->quic_table->obufs_size, obuf->len); return obuf->buf + prefix; } @@ -497,7 +509,7 @@ void knot_quic_stream_ack_data(knot_quic_conn_t *conn, int64_t stream_id, assert(HEAD(*obs) != first); // help CLANG analyzer understand what rem_node did and that further usage of HEAD(*obs) is safe s->obufs_size -= first->len; conn->obufs_size -= first->len; - conn->quic_table->obufs_size -= first->len; + ATOMIC_SUB(conn->quic_table->obufs_size, first->len); s->first_offset += first->len; free(first); if (s->unsent_obuf == first) { @@ -556,6 +568,19 @@ void knot_quic_stream_mark_sent(knot_quic_conn_t *conn, int64_t stream_id, } _public_ +void knot_quic_conn_block(knot_quic_conn_t *conn, bool block) +{ + if (block) { + conn->flags |= KNOT_QUIC_CONN_BLOCKED; + conn->next_expiry = UINT64_MAX; + conn_heap_reschedule(conn, conn->quic_table); + } else { + conn->flags &= ~KNOT_QUIC_CONN_BLOCKED; + quic_conn_mark_used(conn, conn->quic_table); + } +} + +_public_ void knot_quic_cleanup(knot_quic_conn_t *conns[], size_t n_conns) { for (size_t i = 0; i < n_conns; i++) { diff --git a/src/libknot/quic/quic_conn.h b/src/libknot/quic/quic_conn.h index 64ead51..49e0631 100644 --- a/src/libknot/quic/quic_conn.h +++ b/src/libknot/quic/quic_conn.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -29,10 +29,13 @@ #include <stdint.h> #include <sys/uio.h> +#include "contrib/atomic.h" + #define MAX_STREAMS_PER_CONN 10 // this limits the number of un-finished streams per conn (i.e. if response has been recvd with FIN, it doesn't count) +struct gnutls_priority_st; struct ngtcp2_cid; // declaration taken from wherever in ngtcp2 -struct knot_quic_creds; +struct knot_creds; struct knot_quic_reply; struct knot_sweep_stats; @@ -70,6 +73,7 @@ typedef struct { typedef enum { KNOT_QUIC_CONN_HANDSHAKE_DONE = (1 << 0), KNOT_QUIC_CONN_SESSION_TAKEN = (1 << 1), + KNOT_QUIC_CONN_BLOCKED = (1 << 2), } knot_quic_conn_flag_t; typedef struct knot_quic_conn { @@ -111,12 +115,13 @@ typedef struct knot_quic_table { size_t ibufs_max; size_t obufs_max; size_t ibufs_size; - size_t obufs_size; + knot_atomic_size_t obufs_size; size_t udp_payload_limit; // for simplicity not distinguishing IPv4/6 void (*log_cb)(const char *); const char *qlog_dir; uint64_t hash_secret[4]; - struct knot_quic_creds *creds; + struct knot_creds *creds; + struct gnutls_priority_st *priority; struct heap *expiry_heap; knot_quic_cid_t *conns[]; } knot_quic_table_t; @@ -133,7 +138,7 @@ typedef struct knot_quic_table { * \return Allocated table, or NULL. */ knot_quic_table_t *knot_quic_table_new(size_t max_conns, size_t max_ibufs, size_t max_obufs, - size_t udp_payload, struct knot_quic_creds *creds); + size_t udp_payload, struct knot_creds *creds); /*! * \brief Free QUIC table including its contents. @@ -306,6 +311,11 @@ void knot_quic_stream_mark_sent(knot_quic_conn_t *conn, int64_t stream_id, size_t amount_sent); /*! + * \brief (Un)block the connection for incoming/outgoing traffic and sweep. + */ +void knot_quic_conn_block(knot_quic_conn_t *conn, bool block); + +/*! * \brief Free rest of resources of closed conns. * * \param conns Array with recently used conns (possibly NULLs). diff --git a/src/libknot/quic/tls.c b/src/libknot/quic/tls.c new file mode 100644 index 0000000..01172df --- /dev/null +++ b/src/libknot/quic/tls.c @@ -0,0 +1,262 @@ +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + 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 3 of the License, 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 <https://www.gnu.org/licenses/>. + */ + +#include <arpa/inet.h> +#include <assert.h> +#include <gnutls/crypto.h> +#include <gnutls/gnutls.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/socket.h> + +#include "libknot/quic/tls.h" + +#include "contrib/macros.h" +#include "contrib/time.h" +#include "libknot/attribute.h" +#include "libknot/error.h" +#include "libknot/quic/tls_common.h" + +_public_ +knot_tls_ctx_t *knot_tls_ctx_new(struct knot_creds *creds, unsigned io_timeout, + unsigned hs_timeout, bool server) +{ + knot_tls_ctx_t *res = calloc(1, sizeof(*res)); + if (res == NULL) { + return NULL; + } + + res->creds = creds; + res->handshake_timeout = hs_timeout; + res->io_timeout = io_timeout; + res->server = server; + + int ret = gnutls_priority_init2(&res->priority, KNOT_TLS_PRIORITIES, NULL, + GNUTLS_PRIORITY_INIT_DEF_APPEND); + if (ret != GNUTLS_E_SUCCESS) { + free(res); + return NULL; + } + + return res; +} + +_public_ +void knot_tls_ctx_free(knot_tls_ctx_t *ctx) +{ + if (ctx != NULL) { + gnutls_priority_deinit(ctx->priority); + free(ctx); + } +} + +_public_ +knot_tls_conn_t *knot_tls_conn_new(knot_tls_ctx_t *ctx, int sock_fd) +{ + knot_tls_conn_t *res = calloc(1, sizeof(*res)); + if (res == NULL) { + return NULL; + } + res->ctx = ctx; + res->fd = sock_fd; + + int ret = knot_tls_session(&res->session, ctx->creds, ctx->priority, + "\x03""dot", false, ctx->server); + if (ret != KNOT_EOK) { + goto fail; + } + + gnutls_transport_set_int(res->session, sock_fd); // Use internal recv/send/poll. + gnutls_handshake_set_timeout(res->session, ctx->handshake_timeout); + + return res; +fail: + gnutls_deinit(res->session); + free(res); + return NULL; +} + +_public_ +void knot_tls_conn_del(knot_tls_conn_t *conn) +{ + if (conn != NULL && conn->fd_clones_count-- < 1) { + gnutls_deinit(conn->session); + free(conn); + } +} + +_public_ +int knot_tls_handshake(knot_tls_conn_t *conn, bool oneshot) +{ + if (conn->flags & (KNOT_TLS_CONN_HANDSHAKE_DONE | KNOT_TLS_CONN_BLOCKED)) { + return KNOT_EOK; + } + + /* Check if NB socket is writeable. */ + int opt; + socklen_t opt_len = sizeof(opt); + int ret = getsockopt(conn->fd, SOL_SOCKET, SO_ERROR, &opt, &opt_len); + if (ret < 0 || opt == ECONNREFUSED) { + return KNOT_NET_ECONNECT; + } + + gnutls_record_set_timeout(conn->session, conn->ctx->io_timeout); + do { + ret = gnutls_handshake(conn->session); + } while (!oneshot && ret < 0 && gnutls_error_is_fatal(ret) == 0); + + switch (ret) { + case GNUTLS_E_SUCCESS: + conn->flags |= KNOT_TLS_CONN_HANDSHAKE_DONE; + return knot_tls_pin_check(conn->session, conn->ctx->creds); + case GNUTLS_E_TIMEDOUT: + return KNOT_NET_ETIMEOUT; + default: + if (gnutls_error_is_fatal(ret) == 0) { + return KNOT_EAGAIN; + } else { + return KNOT_NET_EHSHAKE; + } + } +} + +#define TIMEOUT_CTX_INIT \ + struct timespec begin, end; \ + if (*timeout_ptr > 0) { \ + clock_gettime(CLOCK_MONOTONIC, &begin); \ + } + +#define TIMEOUT_CTX_UPDATE \ + if (*timeout_ptr > 0) { \ + clock_gettime(CLOCK_MONOTONIC, &end); \ + int running_ms = time_diff_ms(&begin, &end); \ + *timeout_ptr = MAX(*timeout_ptr - running_ms, 0); \ + } + +static ssize_t recv_data(knot_tls_conn_t *conn, void *data, size_t size, int *timeout_ptr) +{ + gnutls_record_set_timeout(conn->session, *timeout_ptr); + + size_t total = 0; + ssize_t res; + while (total < size) { + TIMEOUT_CTX_INIT + res = gnutls_record_recv(conn->session, data + total, size - total); + if (res > 0) { + total += res; + } else if (res == 0) { + return KNOT_ECONNRESET; + } else if (gnutls_error_is_fatal(res) != 0) { + return KNOT_NET_ERECV; + } + TIMEOUT_CTX_UPDATE + gnutls_record_set_timeout(conn->session, *timeout_ptr); + } + + assert(total == size); + return size; +} + +_public_ +ssize_t knot_tls_recv_dns(knot_tls_conn_t *conn, void *data, size_t size) +{ + if (conn == NULL || data == NULL) { + return KNOT_EINVAL; + } + + if (conn->flags & KNOT_TLS_CONN_BLOCKED) { + return 0; + } + + ssize_t ret = knot_tls_handshake(conn, false); + if (ret != KNOT_EOK) { + return ret; + } + + int timeout = conn->ctx->io_timeout; + + uint16_t msg_len; + ret = recv_data(conn, &msg_len, sizeof(msg_len), &timeout); + if (ret != sizeof(msg_len)) { + return ret; + } + + msg_len = ntohs(msg_len); + if (size < msg_len) { + return KNOT_ESPACE; + } + + ret = recv_data(conn, data, msg_len, &timeout); + if (ret != size) { + return ret; + } + + return msg_len; +} + +_public_ +ssize_t knot_tls_send_dns(knot_tls_conn_t *conn, void *data, size_t size) +{ + if (conn == NULL || data == NULL || size > UINT16_MAX) { + return KNOT_EINVAL; + } + + ssize_t res = knot_tls_handshake(conn, false); + if (res != KNOT_EOK) { + return res; + } + + // Enable data buffering. + gnutls_record_cork(conn->session); + + uint16_t msg_len = htons(size); + res = gnutls_record_send(conn->session, &msg_len, sizeof(msg_len)); + if (res != sizeof(msg_len)) { + return KNOT_NET_ESEND; + } + + res = gnutls_record_send(conn->session, data, size); + if (res != size) { + return KNOT_NET_ESEND; + } + + int timeout = conn->ctx->io_timeout, *timeout_ptr = &timeout; + gnutls_record_set_timeout(conn->session, timeout); + + // Send the buffered data. + while (gnutls_record_check_corked(conn->session) > 0) { + TIMEOUT_CTX_INIT + int ret = gnutls_record_uncork(conn->session, 0); + if (ret < 0 && gnutls_error_is_fatal(ret) != 0) { + return ret == GNUTLS_E_TIMEDOUT ? KNOT_ETIMEOUT : + KNOT_NET_ESEND; + } + TIMEOUT_CTX_UPDATE + gnutls_record_set_timeout(conn->session, timeout); + } + + return size; +} + +_public_ +void knot_tls_conn_block(knot_tls_conn_t *conn, bool block) +{ + if (block) { + conn->flags |= KNOT_TLS_CONN_BLOCKED; + } else { + conn->flags &= ~KNOT_TLS_CONN_BLOCKED; + } +} diff --git a/src/libknot/quic/tls.h b/src/libknot/quic/tls.h new file mode 100644 index 0000000..7801ca8 --- /dev/null +++ b/src/libknot/quic/tls.h @@ -0,0 +1,135 @@ +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + 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 3 of the License, 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 <https://www.gnu.org/licenses/>. + */ + +/*! + * \file + * + * \brief Pure TLS functionality. + * + * \addtogroup quic + * @{ + */ + +#pragma once + +#include <stdbool.h> +#include <stdint.h> +#include <sys/types.h> + +struct gnutls_priority_st; + +typedef enum { + KNOT_TLS_CONN_HANDSHAKE_DONE = (1 << 0), + KNOT_TLS_CONN_SESSION_TAKEN = (1 << 1), // unused, to be implemeted later + KNOT_TLS_CONN_BLOCKED = (1 << 2), +} knot_tls_conn_flag_t; + +typedef struct knot_tls_ctx { + struct knot_creds *creds; + struct gnutls_priority_st *priority; + unsigned handshake_timeout; + unsigned io_timeout; + bool server; +} knot_tls_ctx_t; + +typedef struct knot_tls_conn { + struct gnutls_session_int *session; + struct knot_tls_ctx *ctx; + int fd; + unsigned fd_clones_count; + knot_tls_conn_flag_t flags; +} knot_tls_conn_t; + +/*! + * \brief Initialize DoT answering context. + * + * \param creds Certificate credentials. + * \param io_timeout Connections' IO-timeout (in milliseconds). + * \param hs_timeout Handshake timeout (in milliseconds). + * \param server Server context (otherwise client). + * + * \return Initialized context or NULL. + */ +knot_tls_ctx_t *knot_tls_ctx_new(struct knot_creds *creds, unsigned io_timeout, + unsigned hs_timeout, bool server); + +/*! + * \brief Free DoT answering context. + */ +void knot_tls_ctx_free(knot_tls_ctx_t *ctx); + +/*! + * \brief Initialize DoT connection. + * + * \param ctx DoT answering context. + * \param sock_fd Opened TCP connection socket. + * + * \return Connection struct or NULL. + */ +knot_tls_conn_t *knot_tls_conn_new(knot_tls_ctx_t *ctx, int sock_fd); + +/*! + * \brief Free DoT connection struct. + * + * \note Doesn't close the TCP connection socket. + */ +void knot_tls_conn_del(knot_tls_conn_t *conn); + +/*! + * \brief Perform the TLS handshake (via gnutls_handshake()). + * + * \note This is also done by the recv/send functions. + * + * \param conn DoT connection. + * \param oneshot If set, don't wait untill the handshake is finished. + * + * \retval KNOT_EOK Handshake successfully finished. + * \retval KNOT_EGAIN Handshake not finished, call me again. + * \retval KNOT_NET_EHSHAKE Handshake error. + * \retval KNOT_NET_ECONNECT Socket not connected. + */ +int knot_tls_handshake(knot_tls_conn_t *conn, bool oneshot); + +/*! + * \brief Receive a size-word-prefixed DNS message. + * + * \param conn DoT connection. + * \param data Destination buffer. + * \param size Maximum buffer size. + * + * \return Either the DNS message size received or negative error code. + * + * \note The two-byte-size-prefix is stripped upon reception, not stored to the buffer. + */ +ssize_t knot_tls_recv_dns(knot_tls_conn_t *conn, void *data, size_t size); + +/*! + * \brief Send a size-word-prefixed DNS message. + * + * \param conn DoT connection. + * \param data DNS payload. + * \param size Payload size. + * + * \return Either exactly 'size' or a negative error code. + */ +ssize_t knot_tls_send_dns(knot_tls_conn_t *conn, void *data, size_t size); + +/*! + * \brief Set or unset the conection's BLOCKED flag. + */ +void knot_tls_conn_block(knot_tls_conn_t *conn, bool block); + +/*! @} */ diff --git a/src/libknot/quic/tls_common.c b/src/libknot/quic/tls_common.c new file mode 100644 index 0000000..d1647d8 --- /dev/null +++ b/src/libknot/quic/tls_common.c @@ -0,0 +1,472 @@ +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + 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 3 of the License, 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 <https://www.gnu.org/licenses/>. + */ + +#include <fcntl.h> +#include <gnutls/crypto.h> +#include <gnutls/gnutls.h> +#include <gnutls/x509.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <time.h> +#include <unistd.h> + +#include "libknot/quic/tls_common.h" + +#include "contrib/atomic.h" +#include "contrib/sockaddr.h" +#include "contrib/string.h" +#include "libknot/attribute.h" +#include "libknot/error.h" + +typedef struct knot_creds { + knot_atomic_ptr_t cert_creds; // Current credentials. + gnutls_certificate_credentials_t cert_creds_prev; // Previous credentials (for pending connections). + gnutls_anti_replay_t tls_anti_replay; + gnutls_datum_t tls_ticket_key; + bool peer; + uint8_t peer_pin_len; + uint8_t peer_pin[]; +} knot_creds_t; + +static int tls_anti_replay_db_add_func(void *dbf, time_t exp_time, + const gnutls_datum_t *key, + const gnutls_datum_t *data) +{ + return 0; +} + +static void tls_session_ticket_key_free(gnutls_datum_t *ticket) +{ + memzero(ticket->data, ticket->size); + gnutls_free(ticket->data); +} + +static int self_key(gnutls_x509_privkey_t *privkey, const char *key_file) +{ + gnutls_datum_t data = { 0 }; + + int ret = gnutls_x509_privkey_init(privkey); + if (ret != GNUTLS_E_SUCCESS) { + return ret; + } + + int fd = open(key_file, O_RDONLY); + if (fd != -1) { + struct stat stat; + if (fstat(fd, &stat) != 0 || + (data.data = gnutls_malloc(stat.st_size)) == NULL || + read(fd, data.data, stat.st_size) != stat.st_size) { + ret = GNUTLS_E_KEYFILE_ERROR; + goto finish; + } + + data.size = stat.st_size; + ret = gnutls_x509_privkey_import_pkcs8(*privkey, &data, GNUTLS_X509_FMT_PEM, + NULL, GNUTLS_PKCS_PLAIN); + if (ret != GNUTLS_E_SUCCESS) { + goto finish; + } + } else { + ret = gnutls_x509_privkey_generate(*privkey, GNUTLS_PK_EDDSA_ED25519, + GNUTLS_CURVE_TO_BITS(GNUTLS_ECC_CURVE_ED25519), 0); + if (ret != GNUTLS_E_SUCCESS) { + goto finish; + } + + ret = gnutls_x509_privkey_export2_pkcs8(*privkey, GNUTLS_X509_FMT_PEM, NULL, + GNUTLS_PKCS_PLAIN, &data); + if (ret != GNUTLS_E_SUCCESS || + (fd = open(key_file, O_WRONLY | O_CREAT, 0600)) == -1 || + write(fd, data.data, data.size) != data.size) { + ret = GNUTLS_E_KEYFILE_ERROR; + goto finish; + } + } + +finish: + if (fd > -1) { + close(fd); + } + gnutls_free(data.data); + if (ret != GNUTLS_E_SUCCESS) { + gnutls_x509_privkey_deinit(*privkey); + *privkey = NULL; + } + return ret; +} + +static int self_signed_cert(gnutls_certificate_credentials_t tls_cert, + const char *key_file) +{ + gnutls_x509_privkey_t privkey = NULL; + gnutls_x509_crt_t cert = NULL; + + char *hostname = sockaddr_hostname(); + if (hostname == NULL) { + return GNUTLS_E_MEMORY_ERROR; + } + + int ret; + uint8_t serial[16]; + gnutls_rnd(GNUTLS_RND_NONCE, serial, sizeof(serial)); + // Clear the left-most bit to be a positive number (two's complement form). + serial[0] &= 0x7F; + +#define CHK(cmd) if ((ret = (cmd)) != GNUTLS_E_SUCCESS) { goto finish; } +#define NOW_DAYS(days) (time(NULL) + 24 * 3600 * (days)) + + CHK(self_key(&privkey, key_file)); + + CHK(gnutls_x509_crt_init(&cert)); + CHK(gnutls_x509_crt_set_version(cert, 3)); + CHK(gnutls_x509_crt_set_serial(cert, serial, sizeof(serial))); + CHK(gnutls_x509_crt_set_activation_time(cert, NOW_DAYS(-1))); + CHK(gnutls_x509_crt_set_expiration_time(cert, NOW_DAYS(10 * 365))); + CHK(gnutls_x509_crt_set_dn_by_oid(cert, GNUTLS_OID_X520_COMMON_NAME, 0, + hostname, strlen(hostname))); + CHK(gnutls_x509_crt_set_key(cert, privkey)); + CHK(gnutls_x509_crt_sign2(cert, cert, privkey, GNUTLS_DIG_SHA512, 0)); + + ret = gnutls_certificate_set_x509_key(tls_cert, &cert, 1, privkey); + +finish: + free(hostname); + gnutls_x509_crt_deinit(cert); + gnutls_x509_privkey_deinit(privkey); + + return ret; +} + +_public_ +struct knot_creds *knot_creds_init(const char *key_file, const char *cert_file) +{ + knot_creds_t *creds = calloc(1, sizeof(*creds)); + if (creds == NULL) { + return NULL; + } + + int ret = knot_creds_update(creds, key_file, cert_file); + if (ret != KNOT_EOK) { + goto fail; + } + + ret = gnutls_anti_replay_init(&creds->tls_anti_replay); + if (ret != GNUTLS_E_SUCCESS) { + goto fail; + } + gnutls_anti_replay_set_add_function(creds->tls_anti_replay, tls_anti_replay_db_add_func); + gnutls_anti_replay_set_ptr(creds->tls_anti_replay, NULL); + + ret = gnutls_session_ticket_key_generate(&creds->tls_ticket_key); + if (ret != GNUTLS_E_SUCCESS) { + goto fail; + } + + return creds; +fail: + knot_creds_free(creds); + return NULL; +} + +_public_ +struct knot_creds *knot_creds_init_peer(const struct knot_creds *local_creds, + const uint8_t *peer_pin, + uint8_t peer_pin_len) +{ + knot_creds_t *creds = calloc(1, sizeof(*creds) + peer_pin_len); + if (creds == NULL) { + return NULL; + } + + if (local_creds != NULL) { + creds->peer = true; + creds->cert_creds = ATOMIC_GET(local_creds->cert_creds); + } else { + gnutls_certificate_credentials_t new_creds; + int ret = gnutls_certificate_allocate_credentials(&new_creds); + if (ret != GNUTLS_E_SUCCESS) { + free(creds); + return NULL; + } + creds->cert_creds = new_creds; + } + + if (peer_pin_len > 0 && peer_pin != NULL) { + memcpy(creds->peer_pin, peer_pin, peer_pin_len); + creds->peer_pin_len = peer_pin_len; + } + + return creds; +} + +static int creds_cert(gnutls_certificate_credentials_t creds, + struct gnutls_x509_crt_int **cert) +{ + gnutls_x509_crt_t *certs; + unsigned cert_count; + int ret = gnutls_certificate_get_x509_crt(creds, 0, &certs, &cert_count); + if (ret == GNUTLS_E_SUCCESS) { + if (cert_count == 0) { + gnutls_x509_crt_deinit(*certs); + return KNOT_ENOENT; + } + *cert = *certs; + free(certs); + return KNOT_EOK; + } + return KNOT_ERROR; +} + +static int creds_changed(gnutls_certificate_credentials_t creds, + gnutls_certificate_credentials_t prev, + bool self_cert, bool *changed) +{ + if (creds == NULL || prev == NULL) { + *changed = true; + return KNOT_EOK; + } + + gnutls_x509_crt_t cert = NULL, cert_prev = NULL; + + int ret = creds_cert(creds, &cert); + if (ret != KNOT_EOK) { + goto failed; + } + ret = creds_cert(prev, &cert_prev); + if (ret != KNOT_EOK) { + goto failed; + } + + if (self_cert) { + uint8_t pin[KNOT_TLS_PIN_LEN], pin_prev[KNOT_TLS_PIN_LEN]; + size_t pin_size = sizeof(pin), pin_prev_size = sizeof(pin_prev); + + ret = gnutls_x509_crt_get_key_id(cert, GNUTLS_KEYID_USE_SHA256, + pin, &pin_size); + if (ret != KNOT_EOK) { + goto failed; + } + ret = gnutls_x509_crt_get_key_id(cert_prev, GNUTLS_KEYID_USE_SHA256, + pin_prev, &pin_prev_size); + if (ret != KNOT_EOK) { + goto failed; + } + + *changed = (pin_size != pin_prev_size) || + memcmp(pin, pin_prev, pin_size) != 0; + } else { + *changed = (gnutls_x509_crt_equals(cert, cert_prev) == 0); + } + + ret = KNOT_EOK; +failed: + gnutls_x509_crt_deinit(cert); + gnutls_x509_crt_deinit(cert_prev); + + return ret; +} + +_public_ +int knot_creds_update(struct knot_creds *creds, const char *key_file, const char *cert_file) +{ + if (creds == NULL || key_file == NULL) { + return KNOT_EINVAL; + } + + gnutls_certificate_credentials_t new_creds; + int ret = gnutls_certificate_allocate_credentials(&new_creds); + if (ret != GNUTLS_E_SUCCESS) { + return KNOT_ENOMEM; + } + + if (cert_file != NULL) { + ret = gnutls_certificate_set_x509_key_file(new_creds, + cert_file, key_file, + GNUTLS_X509_FMT_PEM); + } else { + ret = self_signed_cert(new_creds, key_file); + } + if (ret != GNUTLS_E_SUCCESS) { + gnutls_certificate_free_credentials(new_creds); + return KNOT_EFILE; + } + + bool changed = false; + ret = creds_changed(new_creds, ATOMIC_GET(creds->cert_creds), + cert_file == NULL, &changed); + if (ret != KNOT_EOK) { + gnutls_certificate_free_credentials(new_creds); + return ret; + } + + if (changed) { + if (creds->cert_creds_prev != NULL) { + gnutls_certificate_free_credentials(creds->cert_creds_prev); + } + creds->cert_creds_prev = ATOMIC_XCHG(creds->cert_creds, new_creds); + } else { + gnutls_certificate_free_credentials(new_creds); + } + + return KNOT_EOK; +} + +_public_ +int knot_creds_cert(struct knot_creds *creds, struct gnutls_x509_crt_int **cert) +{ + if (creds == NULL || cert == NULL) { + return KNOT_EINVAL; + } + + return creds_cert(ATOMIC_GET(creds->cert_creds), cert); +} + +_public_ +void knot_creds_free(struct knot_creds *creds) +{ + if (creds == NULL) { + return; + } + + if (!creds->peer && creds->cert_creds != NULL) { + gnutls_certificate_free_credentials(creds->cert_creds); + if (creds->cert_creds_prev != NULL) { + gnutls_certificate_free_credentials(creds->cert_creds_prev); + } + } + gnutls_anti_replay_deinit(creds->tls_anti_replay); + if (creds->tls_ticket_key.data != NULL) { + tls_session_ticket_key_free(&creds->tls_ticket_key); + } + free(creds); +} + +_public_ +int knot_tls_session(struct gnutls_session_int **session, + struct knot_creds *creds, + struct gnutls_priority_st *priority, + const char *alpn, + bool early_data, + bool server) +{ + if (session == NULL || creds == NULL || priority == NULL || alpn == NULL) { + return KNOT_EINVAL; + } + + gnutls_init_flags_t flags = GNUTLS_NO_SIGNAL; + if (early_data) { + flags |= GNUTLS_ENABLE_EARLY_DATA; +#ifdef ENABLE_QUIC // Next flags aren't available in older GnuTLS versions. + flags |= GNUTLS_NO_AUTO_SEND_TICKET | GNUTLS_NO_END_OF_EARLY_DATA; +#endif + } + + int ret = gnutls_init(session, (server ? GNUTLS_SERVER : GNUTLS_CLIENT) | flags); + if (ret == GNUTLS_E_SUCCESS) { + gnutls_certificate_send_x509_rdn_sequence(*session, 1); + gnutls_certificate_server_set_request(*session, GNUTLS_CERT_REQUEST); + ret = gnutls_priority_set(*session, priority); + } + if (server && ret == GNUTLS_E_SUCCESS) { + ret = gnutls_session_ticket_enable_server(*session, &creds->tls_ticket_key); + } + if (ret == GNUTLS_E_SUCCESS) { + const gnutls_datum_t alpn_datum = { (void *)&alpn[1], alpn[0] }; + gnutls_alpn_set_protocols(*session, &alpn_datum, 1, GNUTLS_ALPN_MANDATORY); + if (early_data) { + gnutls_record_set_max_early_data_size(*session, 0xffffffffu); + } + if (server) { + gnutls_anti_replay_enable(*session, creds->tls_anti_replay); + } + ret = gnutls_credentials_set(*session, GNUTLS_CRD_CERTIFICATE, + ATOMIC_GET(creds->cert_creds)); + } + if (ret != GNUTLS_E_SUCCESS) { + gnutls_deinit(*session); + *session = NULL; + } + return ret == GNUTLS_E_SUCCESS ? KNOT_EOK : KNOT_ERROR; +} + +_public_ +void knot_tls_pin(struct gnutls_session_int *session, uint8_t *pin, + size_t *pin_size, bool local) +{ + if (session == NULL) { + goto error; + } + + const gnutls_datum_t *data = NULL; + if (local) { + data = gnutls_certificate_get_ours(session); + } else { + unsigned count = 0; + data = gnutls_certificate_get_peers(session, &count); + if (count == 0) { + goto error; + } + } + if (data == NULL) { + goto error; + } + + gnutls_x509_crt_t cert; + int ret = gnutls_x509_crt_init(&cert); + if (ret != GNUTLS_E_SUCCESS) { + goto error; + } + + ret = gnutls_x509_crt_import(cert, data, GNUTLS_X509_FMT_DER); + if (ret != GNUTLS_E_SUCCESS) { + gnutls_x509_crt_deinit(cert); + goto error; + } + + ret = gnutls_x509_crt_get_key_id(cert, GNUTLS_KEYID_USE_SHA256, pin, pin_size); + if (ret != GNUTLS_E_SUCCESS) { + gnutls_x509_crt_deinit(cert); + goto error; + } + + gnutls_x509_crt_deinit(cert); + + return; +error: + if (pin_size != NULL) { + *pin_size = 0; + } +} + +_public_ +int knot_tls_pin_check(struct gnutls_session_int *session, + struct knot_creds *creds) +{ + if (creds->peer_pin_len == 0) { + return KNOT_EOK; + } + + uint8_t pin[KNOT_TLS_PIN_LEN]; + size_t pin_size = sizeof(pin); + knot_tls_pin(session, pin, &pin_size, false); + if (pin_size != creds->peer_pin_len || + const_time_memcmp(pin, creds->peer_pin, pin_size) != 0) { + return KNOT_EBADCERTKEY; + } + + return KNOT_EOK; +} diff --git a/src/libknot/quic/tls_common.h b/src/libknot/quic/tls_common.h new file mode 100644 index 0000000..934f256 --- /dev/null +++ b/src/libknot/quic/tls_common.h @@ -0,0 +1,134 @@ +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + 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 3 of the License, 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 <https://www.gnu.org/licenses/>. + */ + +/*! + * \file + * + * \brief Credentials handling common to QUIC and TLS. + * + * \addtogroup quic + * @{ + */ + +#pragma once + +#include <stdbool.h> +#include <stddef.h> +#include <stdint.h> + +#define KNOT_TLS_PIN_LEN 32 +#define KNOT_TLS_PRIORITIES "-VERS-ALL:+VERS-TLS1.3:" \ + "-GROUP-ALL:+GROUP-X25519:+GROUP-SECP256R1:" \ + "+GROUP-SECP384R1:+GROUP-SECP521R1" + +struct gnutls_priority_st; +struct gnutls_session_int; +struct gnutls_x509_crt_int; +struct knot_creds; + +/*! + * \brief Init server TLS key and certificate for DoQ. + * + * \param key_file Key PEM file path/name. + * \param cert_file X509 certificate PEM file path/name (NULL if auto-generated). + * + * \return Initialized creds. + */ +struct knot_creds *knot_creds_init(const char *key_file, const char *cert_file); + +/*! + * \brief Init peer TLS key and certificate for DoQ. + * + * \param local_creds Local credentials if server. + * \param peer_pin Optional peer certificate pin to check. + * \param peer_pin_len Length of the peer pin. Set 0 if not specified. + * + * \return Initialized creds. + */ +struct knot_creds *knot_creds_init_peer(const struct knot_creds *local_creds, + const uint8_t *peer_pin, + uint8_t peer_pin_len); + +/*! + * \brief Load new server TLS key and certificate for DoQ. + * + * \param creds Server credentials where key/cert pair will be updated. + * \param key_file Key PEM file path/name. + * \param cert_file X509 certificate PEM file path/name (NULL if auto-generated). + * + * \return KNOT_E* + */ +int knot_creds_update(struct knot_creds *creds, const char *key_file, const char *cert_file); + +/*! + * \brief Gets the certificate from credentials. + * + * \param creds TLS credentials. + * \param cert Output certificate. + * + * \return KNOT_E* + */ +int knot_creds_cert(struct knot_creds *creds, struct gnutls_x509_crt_int **cert); + +/*! + * \brief Deinit server TLS certificate for DoQ. + */ +void knot_creds_free(struct knot_creds *creds); + +/*! + * \brief Initialize GnuTLS session with credentials, ALPN, etc. + * + * \param session Out: initialized GnuTLS session struct. + * \param creds Certificate credentials. + * \param priority Session priority configuration. + * \param alpn ALPN string, first byte is the string length. + * \param early_data Allow early data. + * \param server Should be server session (otherwise client). + * + * \return KNOT_E* + */ +int knot_tls_session(struct gnutls_session_int **session, + struct knot_creds *creds, + struct gnutls_priority_st *priority, + const char *alpn, + bool early_data, + bool server); + +/*! + * \brief Gets local or remote certificate pin. + * + * \note Zero output pin_size value means no certificate available or error. + * + * \param session TLS connection. + * \param pin Output certificate pin. + * \param pin_size Input size of the storage / output size of the stored pin. + * \param local Local or remote certificate indication. + */ +void knot_tls_pin(struct gnutls_session_int *session, uint8_t *pin, + size_t *pin_size, bool local); + +/*! + * \brief Checks remote certificate pin in the session against credentials. + * + * \param session TLS connection. + * \param creds TLS credentials. + * + * \return KNOT_EOK or KNOT_EBADCERTKEY + */ +int knot_tls_pin_check(struct gnutls_session_int *session, + struct knot_creds *creds); + +/*! @} */ diff --git a/src/libknot/rrset-dump.c b/src/libknot/rrset-dump.c index ea406ca..9fac99d 100644 --- a/src/libknot/rrset-dump.c +++ b/src/libknot/rrset-dump.c @@ -508,10 +508,46 @@ static void wire_len_data_encode_to_str(rrset_dump_params_t *p, } } -static void wire_data_omit(rrset_dump_params_t *p) +static void wire_data_omit(rrset_dump_params_t *p, + const size_t len_len, + const bool print_len) { CHECK_PRET + size_t in_len; + + // First len_len bytes are data length. + CHECK_INMAX(len_len) + + // Read data length. + switch (len_len) { + case 0: + in_len = p->in_max; + break; + case 2: + in_len = knot_wire_read_u16(p->in); + break; + default: + p->ret = -1; + return; + } + + // If required print data length. + if (print_len == true && len_len != 0) { + assert(len_len == 2); + wire_num16_to_str(p); + CHECK_PRET + + // If something follows, print one space character. + if (in_len > 0) { + dump_string(p, " "); + CHECK_PRET + } + } else { + p->in += len_len; + p->in_max -= len_len; + } + const char *omit_message = "[omitted]"; const size_t omlen = strlen(omit_message); @@ -527,8 +563,8 @@ static void wire_data_omit(rrset_dump_params_t *p) STRING_TERMINATION - p->in += p->in_max; - p->in_max = 0; + p->in += in_len; + p->in_max -= in_len; } static void wire_dnskey_to_tag(rrset_dump_params_t *p) @@ -1735,6 +1771,10 @@ static void dnskey_info(const uint8_t *rdata, #define DUMP_TYPE wire_type_to_str(p); CHECK_RET(p); #define DUMP_HEX wire_data_encode_to_str(p, &hex_encode, \ &hex_encode_alloc); CHECK_RET(p); +#define DUMP_OMIT wire_data_omit(p, 0, false); CHECK_RET(p); +#define DUMP_HEX_OMIT if (p->style->hide_crypto) { DUMP_OMIT; } \ + else if (p->style->wrap) { WRAP_INIT; DUMP_HEX; WRAP_END; } \ + else { DUMP_HEX; } #define DUMP_BASE64 wire_data_encode_to_str(p, &knot_base64_encode, \ &knot_base64_encode_alloc); CHECK_RET(p); #define DUMP_HASH wire_len_data_encode_to_str(p, &knot_base32hex_encode, \ @@ -1743,9 +1783,9 @@ static void dnskey_info(const uint8_t *rdata, 1, false, "-"); CHECK_RET(p); #define DUMP_TSIG_DGST wire_len_data_encode_to_str(p, &knot_base64_encode, \ 2, true, ""); CHECK_RET(p); +#define DUMP_TSIG_OMIT wire_data_omit(p, 2, true); CHECK_RET(p); #define DUMP_TSIG_DATA wire_len_data_encode_to_str(p, &num48_encode, \ 2, true, ""); CHECK_RET(p); -#define DUMP_OMIT wire_data_omit(p); CHECK_RET(p); #define DUMP_KEY_OMIT wire_dnskey_to_tag(p); CHECK_RET(p); #define DUMP_TEXT wire_text_to_str1(p, true, false); CHECK_RET(p); #define DUMP_LONG_TEXT wire_text_to_str(p, p->in_max, NULL, true, false); CHECK_RET(p); @@ -1923,16 +1963,17 @@ static int dump_naptr(DUMP_PARAMS) static int dump_cert(DUMP_PARAMS) { - if (p->style->wrap) { - DUMP_NUM16; DUMP_SPACE; - DUMP_NUM16; DUMP_SPACE; - DUMP_NUM8; DUMP_SPACE; WRAP_INIT; + DUMP_NUM16; DUMP_SPACE; + DUMP_NUM16; DUMP_SPACE; + DUMP_NUM8; DUMP_SPACE; + + if (p->style->hide_crypto) { + DUMP_OMIT; + } else if (p->style->wrap) { + WRAP_INIT; DUMP_BASE64; WRAP_END; } else { - DUMP_NUM16; DUMP_SPACE; - DUMP_NUM16; DUMP_SPACE; - DUMP_NUM8; DUMP_SPACE; DUMP_BASE64; } @@ -1982,34 +2023,19 @@ static int dump_apl(DUMP_PARAMS) static int dump_ds(DUMP_PARAMS) { - if (p->style->wrap) { - DUMP_NUM16; DUMP_SPACE; - DUMP_NUM8; DUMP_SPACE; - DUMP_NUM8; DUMP_SPACE; WRAP_INIT; - DUMP_HEX; - WRAP_END; - } else { - DUMP_NUM16; DUMP_SPACE; - DUMP_NUM8; DUMP_SPACE; - DUMP_NUM8; DUMP_SPACE; - DUMP_HEX; - } + DUMP_NUM16; DUMP_SPACE; + DUMP_NUM8; DUMP_SPACE; + DUMP_NUM8; DUMP_SPACE; + DUMP_HEX_OMIT; DUMP_END; } static int dump_sshfp(DUMP_PARAMS) { - if (p->style->wrap) { - DUMP_NUM8; DUMP_SPACE; - DUMP_NUM8; DUMP_SPACE; WRAP_INIT; - DUMP_HEX; - WRAP_END; - } else { - DUMP_NUM8; DUMP_SPACE; - DUMP_NUM8; DUMP_SPACE; - DUMP_HEX; - } + DUMP_NUM8; DUMP_SPACE; + DUMP_NUM8; DUMP_SPACE; + DUMP_HEX_OMIT; DUMP_END; } @@ -2067,7 +2093,9 @@ static int dump_nsec(DUMP_PARAMS) static int dump_dhcid(DUMP_PARAMS) { - if (p->style->wrap) { + if (p->style->hide_crypto) { + DUMP_OMIT; + } else if (p->style->wrap) { WRAP_INIT; DUMP_BASE64; WRAP_END; @@ -2112,18 +2140,10 @@ static int dump_nsec3param(DUMP_PARAMS) static int dump_tlsa(DUMP_PARAMS) { - if (p->style->wrap) { - DUMP_NUM8; DUMP_SPACE; - DUMP_NUM8; DUMP_SPACE; - DUMP_NUM8; DUMP_SPACE; WRAP_INIT; - DUMP_HEX; - WRAP_END; - } else { - DUMP_NUM8; DUMP_SPACE; - DUMP_NUM8; DUMP_SPACE; - DUMP_NUM8; DUMP_SPACE; - DUMP_HEX; - } + DUMP_NUM8; DUMP_SPACE; + DUMP_NUM8; DUMP_SPACE; + DUMP_NUM8; DUMP_SPACE; + DUMP_HEX_OMIT; DUMP_END; } @@ -2139,18 +2159,10 @@ static int dump_csync(DUMP_PARAMS) static int dump_zonemd(DUMP_PARAMS) { - if (p->style->wrap) { - DUMP_NUM32; DUMP_SPACE; - DUMP_NUM8; DUMP_SPACE; - DUMP_NUM8; DUMP_SPACE; WRAP_INIT; - DUMP_HEX; - WRAP_END; - } else { - DUMP_NUM32; DUMP_SPACE; - DUMP_NUM8; DUMP_SPACE; - DUMP_NUM8; DUMP_SPACE; - DUMP_HEX; - } + DUMP_NUM32; DUMP_SPACE; + DUMP_NUM8; DUMP_SPACE; + DUMP_NUM8; DUMP_SPACE; + DUMP_HEX_OMIT; DUMP_END; } @@ -2184,7 +2196,11 @@ static int dump_tsig(DUMP_PARAMS) DUMP_DNAME; DUMP_SPACE; DUMP_NUM48; DUMP_SPACE; DUMP_NUM16; DUMP_SPACE; WRAP_INIT; - DUMP_TSIG_DGST; WRAP_LINE; + if (p->style->hide_crypto) { + DUMP_TSIG_OMIT; WRAP_LINE; + } else { + DUMP_TSIG_DGST; WRAP_LINE; + } DUMP_NUM16; DUMP_SPACE; DUMP_TSIG_RCODE; DUMP_SPACE; DUMP_TSIG_DATA; @@ -2193,7 +2209,11 @@ static int dump_tsig(DUMP_PARAMS) DUMP_DNAME; DUMP_SPACE; DUMP_NUM48; DUMP_SPACE; DUMP_NUM16; DUMP_SPACE; - DUMP_TSIG_DGST; DUMP_SPACE; + if (p->style->hide_crypto) { + DUMP_TSIG_OMIT; DUMP_SPACE; + } else { + DUMP_TSIG_DGST; DUMP_SPACE; + } DUMP_NUM16; DUMP_SPACE; DUMP_TSIG_RCODE; DUMP_SPACE; DUMP_TSIG_DATA; diff --git a/src/libknot/rrtype/tsig.c b/src/libknot/rrtype/tsig.c index 83f8436..0002963 100644 --- a/src/libknot/rrtype/tsig.c +++ b/src/libknot/rrtype/tsig.c @@ -245,7 +245,11 @@ int knot_tsig_rdata_set_other_data(knot_rrset_t *tsig, uint16_t len, _public_ const knot_dname_t *knot_tsig_rdata_alg_name(const knot_rrset_t *tsig) { - return knot_rdataset_at(&tsig->rrs, 0)->data; + const knot_rdata_t *rr_data = knot_rdataset_at(&tsig->rrs, 0); + if (!rr_data) { + return NULL; + } + return rr_data->data; } _public_ diff --git a/src/libknot/version.h b/src/libknot/version.h index 38e0b74..8e21f49 100644 --- a/src/libknot/version.h +++ b/src/libknot/version.h @@ -17,8 +17,8 @@ #pragma once #define KNOT_VERSION_MAJOR 3 -#define KNOT_VERSION_MINOR 3 -#define KNOT_VERSION_PATCH 0x09 +#define KNOT_VERSION_MINOR 4 +#define KNOT_VERSION_PATCH 0x00 #define KNOT_VERSION_HEX ((KNOT_VERSION_MAJOR << 16) | \ (KNOT_VERSION_MINOR << 8) | \ diff --git a/src/libknot/xdp/Makefile.in b/src/libknot/xdp/Makefile.in index 8aa77ce..f065f3e 100644 --- a/src/libknot/xdp/Makefile.in +++ b/src/libknot/xdp/Makefile.in @@ -270,6 +270,8 @@ infodir = @infodir@ install_sh = @install_sh@ libbpf_CFLAGS = @libbpf_CFLAGS@ libbpf_LIBS = @libbpf_LIBS@ +libdbus_CFLAGS = @libdbus_CFLAGS@ +libdbus_LIBS = @libdbus_LIBS@ libdir = @libdir@ libdnssec_SONAME = @libdnssec_SONAME@ libdnssec_SOVERSION = @libdnssec_SOVERSION@ @@ -281,8 +283,6 @@ libfstrm_CFLAGS = @libfstrm_CFLAGS@ libfstrm_LIBS = @libfstrm_LIBS@ libidn2_CFLAGS = @libidn2_CFLAGS@ libidn2_LIBS = @libidn2_LIBS@ -libidn_CFLAGS = @libidn_CFLAGS@ -libidn_LIBS = @libidn_LIBS@ libknot_SONAME = @libknot_SONAME@ libknot_SOVERSION = @libknot_SOVERSION@ libknot_VERSION_INFO = @libknot_VERSION_INFO@ @@ -300,7 +300,6 @@ libprotobuf_c_CFLAGS = @libprotobuf_c_CFLAGS@ libprotobuf_c_LIBS = @libprotobuf_c_LIBS@ liburcu_CFLAGS = @liburcu_CFLAGS@ liburcu_LIBS = @liburcu_LIBS@ -liburcu_PKGCONFIG = @liburcu_PKGCONFIG@ libxdp_CFLAGS = @libxdp_CFLAGS@ libxdp_LIBS = @libxdp_LIBS@ libzscanner_SONAME = @libzscanner_SONAME@ diff --git a/src/libknot/xdp/bpf-user.h b/src/libknot/xdp/bpf-user.h index 37aac61..b76c9d6 100644 --- a/src/libknot/xdp/bpf-user.h +++ b/src/libknot/xdp/bpf-user.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -60,8 +60,10 @@ struct kxsk_umem { /*! The memory frames. */ struct umem_frame *frames; + /*! Size of RX and TX rings. */ + uint16_t ring_size; /*! The number of free frames (for TX). */ - uint32_t tx_free_count; + uint16_t tx_free_count; /*! Stack of indices of the free frames (for TX). */ uint16_t tx_free_indices[]; }; @@ -82,15 +84,15 @@ struct knot_xdp_socket { /*! If non-NULL, it's a mocked socket with this send function. */ int (*send_mock)(struct knot_xdp_socket *, const knot_xdp_msg_t[], uint32_t, uint32_t *); - /*! The kernel has to be woken up by a syscall indication. */ - bool kernel_needs_wakeup; - /*! The limit of frame size. */ unsigned frame_limit; /*! Mapping of interface indices to VLAN tags. */ uint16_t *vlan_map; uint16_t vlan_map_max; + + /*! Enabled preferred busy polling. */ + bool busy_poll; }; /*! diff --git a/src/libknot/xdp/tcp.c b/src/libknot/xdp/tcp.c index eae73a9..d219db9 100644 --- a/src/libknot/xdp/tcp.c +++ b/src/libknot/xdp/tcp.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -287,172 +287,162 @@ static void conn_update(knot_tcp_conn_t *conn, const knot_xdp_msg_t *msg) } _public_ -int knot_tcp_recv(knot_tcp_relay_t *relays, knot_xdp_msg_t msgs[], uint32_t msg_count, +int knot_tcp_recv(knot_tcp_relay_t *relay, knot_xdp_msg_t *msg, knot_tcp_table_t *tcp_table, knot_tcp_table_t *syn_table, knot_tcp_ignore_t ignore) { - if (msg_count == 0) { - return KNOT_EOK; - } - if (relays == NULL || msgs == NULL || tcp_table == NULL) { + if (relay == NULL || msg == NULL || tcp_table == NULL) { return KNOT_EINVAL; } - memset(relays, 0, msg_count * sizeof(*relays)); + memset(relay, 0, sizeof(*relay)); - knot_tcp_relay_t *relay = relays; int ret = KNOT_EOK; - for (knot_xdp_msg_t *msg = msgs; msg != msgs + msg_count && ret == KNOT_EOK; msg++) { - if (!(msg->flags & KNOT_XDP_MSG_TCP)) { - continue; - } + if (!(msg->flags & KNOT_XDP_MSG_TCP)) { + return KNOT_EOK; + } - uint64_t conn_hash = 0; - knot_tcp_conn_t **pconn = tcp_table_lookup(&msg->ip_from, &msg->ip_to, - &conn_hash, tcp_table); - knot_tcp_conn_t *conn = *pconn; - bool seq_ack_match = check_seq_ack(msg, conn); - if (seq_ack_match) { - assert(conn->mss != 0); - conn_update(conn, msg); - - rem_align_pointers(conn, tcp_table); - rem_node(tcp_conn_node(conn)); - add_tail(tcp_table_timeout(tcp_table), tcp_conn_node(conn)); - - if (msg->flags & KNOT_XDP_MSG_ACK) { - conn->acked = msg->ackno; - knot_tcp_outbufs_ack(&conn->outbufs, msg->ackno, &tcp_table->outbufs_total); - } + uint64_t conn_hash = 0; + knot_tcp_conn_t **pconn = tcp_table_lookup(&msg->ip_from, &msg->ip_to, + &conn_hash, tcp_table); + knot_tcp_conn_t *conn = *pconn; + bool seq_ack_match = check_seq_ack(msg, conn); + if (seq_ack_match) { + assert(conn->mss != 0); + conn_update(conn, msg); + + rem_align_pointers(conn, tcp_table); + rem_node(tcp_conn_node(conn)); + add_tail(tcp_table_timeout(tcp_table), tcp_conn_node(conn)); + + if (msg->flags & KNOT_XDP_MSG_ACK) { + conn->acked = msg->ackno; + knot_tcp_outbufs_ack(&conn->outbufs, msg->ackno, &tcp_table->outbufs_total); } + } - relay->msg = msg; - relay->conn = conn; + relay->msg = msg; + relay->conn = conn; - // process incoming data - if (seq_ack_match && (msg->flags & KNOT_XDP_MSG_ACK) && msg->payload.iov_len > 0) { - if (!(ignore & XDP_TCP_IGNORE_DATA_ACK)) { - relay->auto_answer = KNOT_XDP_MSG_ACK; - } - ret = knot_tcp_inbufs_upd(&conn->inbuf, msg->payload, false, - &relay->inbf, &tcp_table->inbufs_total); - if (ret != KNOT_EOK) { - break; - } - if (conn->inbuf.iov_len > 0 && tcp_table->next_ibuf == NULL) { - tcp_table->next_ibuf = conn; - } + // process incoming data + if (seq_ack_match && (msg->flags & KNOT_XDP_MSG_ACK) && msg->payload.iov_len > 0) { + if (!(ignore & XDP_TCP_IGNORE_DATA_ACK)) { + relay->auto_answer = KNOT_XDP_MSG_ACK; + } + ret = knot_tcp_inbufs_upd(&conn->inbuf, msg->payload, false, + &relay->inbf, &tcp_table->inbufs_total); + if (ret != KNOT_EOK) { + return ret; + } + if (conn->inbuf.iov_len > 0 && tcp_table->next_ibuf == NULL) { + tcp_table->next_ibuf = conn; } + } - // process TCP connection state - switch (msg->flags & (KNOT_XDP_MSG_SYN | KNOT_XDP_MSG_ACK | - KNOT_XDP_MSG_FIN | KNOT_XDP_MSG_RST)) { - case KNOT_XDP_MSG_SYN: - case (KNOT_XDP_MSG_SYN | KNOT_XDP_MSG_ACK): - if (conn == NULL) { - bool synack = (msg->flags & KNOT_XDP_MSG_ACK); - - knot_tcp_table_t *add_table = tcp_table; - if (syn_table != NULL) { - if (synack) { - break; // creating conn based on SYN+ACK is only for kxdpgun, disallow in knotd - } - add_table = syn_table; - if (*tcp_table_lookup(&msg->ip_from, &msg->ip_to, &conn_hash, syn_table) != NULL) { - break; - } - } + // process TCP connection state + switch (msg->flags & (KNOT_XDP_MSG_SYN | KNOT_XDP_MSG_ACK | + KNOT_XDP_MSG_FIN | KNOT_XDP_MSG_RST)) { + case KNOT_XDP_MSG_SYN: + case (KNOT_XDP_MSG_SYN | KNOT_XDP_MSG_ACK): + if (conn == NULL) { + bool synack = (msg->flags & KNOT_XDP_MSG_ACK); - ret = tcp_table_add(msg, conn_hash, add_table, &relay->conn); - if (ret == KNOT_EOK) { - relay->action = synack ? XDP_TCP_ESTABLISH : XDP_TCP_SYN; - if (!(ignore & XDP_TCP_IGNORE_ESTABLISH)) { - relay->auto_answer = synack ? KNOT_XDP_MSG_ACK : (KNOT_XDP_MSG_SYN | KNOT_XDP_MSG_ACK); - } - - conn = relay->conn; - conn->state = synack ? XDP_TCP_NORMAL: XDP_TCP_ESTABLISHING; - conn->mss = MAX(msg->mss, 536); // minimal MSS, most importantly not zero! - conn->window_scale = msg->win_scale; - conn_update(conn, msg); - if (!synack) { - conn->acked = dnssec_random_uint32_t(); - conn->ackno = conn->acked; - } + knot_tcp_table_t *add_table = tcp_table; + if (syn_table != NULL) { + if (synack) { + break; // creating conn based on SYN+ACK is only for kxdpgun, disallow in knotd + } + add_table = syn_table; + if (*tcp_table_lookup(&msg->ip_from, &msg->ip_to, &conn_hash, syn_table) != NULL) { + break; } - } else { - relay->auto_answer = KNOT_XDP_MSG_ACK; } - break; - case KNOT_XDP_MSG_ACK: - if (!seq_ack_match) { - if (syn_table != NULL && msg->payload.iov_len == 0 && conn == NULL && - (pconn = tcp_table_lookup(&msg->ip_from, &msg->ip_to, &conn_hash, syn_table)) != NULL && - (conn = *pconn) != NULL && check_seq_ack(msg, conn)) { - // move conn from syn_table to tcp_table - tcp_table_remove(pconn, syn_table); - tcp_table_insert(conn, conn_hash, tcp_table); - relay->conn = conn; - relay->action = XDP_TCP_ESTABLISH; - conn->state = XDP_TCP_NORMAL; - conn_update(conn, msg); + + ret = tcp_table_add(msg, conn_hash, add_table, &relay->conn); + if (ret == KNOT_EOK) { + relay->action = synack ? XDP_TCP_ESTABLISH : XDP_TCP_SYN; + if (!(ignore & XDP_TCP_IGNORE_ESTABLISH)) { + relay->auto_answer = synack ? KNOT_XDP_MSG_ACK : (KNOT_XDP_MSG_SYN | KNOT_XDP_MSG_ACK); } - } else { - switch (conn->state) { - case XDP_TCP_NORMAL: - case XDP_TCP_CLOSING1: // just a mess, ignore - break; - case XDP_TCP_ESTABLISHING: - conn->state = XDP_TCP_NORMAL; - relay->action = XDP_TCP_ESTABLISH; - break; - case XDP_TCP_CLOSING2: - if (msg->payload.iov_len == 0) { // otherwise ignore close - tcp_table_remove(pconn, tcp_table); - relay->answer = XDP_TCP_FREE; - } - break; + + conn = relay->conn; + conn->state = synack ? XDP_TCP_NORMAL: XDP_TCP_ESTABLISHING; + conn->mss = MAX(msg->mss, 536); // minimal MSS, most importantly not zero! + conn->window_scale = msg->win_scale; + conn_update(conn, msg); + if (!synack) { + conn->acked = dnssec_random_uint32_t(); + conn->ackno = conn->acked; } } - break; - case (KNOT_XDP_MSG_FIN | KNOT_XDP_MSG_ACK): - if (ignore & XDP_TCP_IGNORE_FIN) { - break; + } else { + relay->auto_answer = KNOT_XDP_MSG_ACK; + } + break; + case KNOT_XDP_MSG_ACK: + if (!seq_ack_match) { + if (syn_table != NULL && msg->payload.iov_len == 0 && conn == NULL && + (pconn = tcp_table_lookup(&msg->ip_from, &msg->ip_to, &conn_hash, syn_table)) != NULL && + (conn = *pconn) != NULL && check_seq_ack(msg, conn)) { + // move conn from syn_table to tcp_table + tcp_table_remove(pconn, syn_table); + tcp_table_insert(conn, conn_hash, tcp_table); + relay->conn = conn; + relay->action = XDP_TCP_ESTABLISH; + conn->state = XDP_TCP_NORMAL; + conn_update(conn, msg); } - if (!seq_ack_match) { - if (conn != NULL) { - relay->auto_answer = KNOT_XDP_MSG_RST; - relay->auto_seqno = msg->ackno; - } // else ignore. It would be better and possible, but no big value for the price of CPU. - } else { - if (conn->state == XDP_TCP_CLOSING1) { - relay->action = XDP_TCP_CLOSE; - relay->auto_answer = KNOT_XDP_MSG_ACK; - relay->answer = XDP_TCP_FREE; + } else { + switch (conn->state) { + case XDP_TCP_NORMAL: + case XDP_TCP_CLOSING1: // just a mess, ignore + break; + case XDP_TCP_ESTABLISHING: + conn->state = XDP_TCP_NORMAL; + relay->action = XDP_TCP_ESTABLISH; + break; + case XDP_TCP_CLOSING2: + if (msg->payload.iov_len == 0) { // otherwise ignore close tcp_table_remove(pconn, tcp_table); - } else if (msg->payload.iov_len == 0) { // otherwise ignore FIN - relay->action = XDP_TCP_CLOSE; - relay->auto_answer = KNOT_XDP_MSG_FIN | KNOT_XDP_MSG_ACK; - conn->state = XDP_TCP_CLOSING2; + relay->answer = XDP_TCP_FREE; } + break; } + } + break; + case (KNOT_XDP_MSG_FIN | KNOT_XDP_MSG_ACK): + if (ignore & XDP_TCP_IGNORE_FIN) { break; - case KNOT_XDP_MSG_RST: - if (conn != NULL && msg->seqno == conn->seqno) { - relay->action = XDP_TCP_RESET; - tcp_table_remove(pconn, tcp_table); - relay->answer = XDP_TCP_FREE; - } else if (conn != NULL) { + } + if (!seq_ack_match) { + if (conn != NULL) { + relay->auto_answer = KNOT_XDP_MSG_RST; + relay->auto_seqno = msg->ackno; + } // else ignore. It would be better and possible, but no big value for the price of CPU. + } else { + if (conn->state == XDP_TCP_CLOSING1) { + relay->action = XDP_TCP_CLOSE; relay->auto_answer = KNOT_XDP_MSG_ACK; + relay->answer = XDP_TCP_FREE; + tcp_table_remove(pconn, tcp_table); + } else if (msg->payload.iov_len == 0) { // otherwise ignore FIN + relay->action = XDP_TCP_CLOSE; + relay->auto_answer = KNOT_XDP_MSG_FIN | KNOT_XDP_MSG_ACK; + conn->state = XDP_TCP_CLOSING2; } - break; - default: - break; } - - if (!knot_tcp_relay_empty(relay)) { - relay++; + break; + case KNOT_XDP_MSG_RST: + if (conn != NULL && msg->seqno == conn->seqno) { + relay->action = XDP_TCP_RESET; + tcp_table_remove(pconn, tcp_table); + relay->answer = XDP_TCP_FREE; + } else if (conn != NULL) { + relay->auto_answer = KNOT_XDP_MSG_ACK; } + break; + default: + break; } return ret; diff --git a/src/libknot/xdp/tcp.h b/src/libknot/xdp/tcp.h index 09fe652..39a30fd 100644 --- a/src/libknot/xdp/tcp.h +++ b/src/libknot/xdp/tcp.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -148,18 +148,19 @@ knot_tcp_table_t *knot_tcp_table_new(size_t size, knot_tcp_table_t *secret_share void knot_tcp_table_free(knot_tcp_table_t *table); /*! - * \brief Process received packets, prepare automatic responses (e.g. ACK), pick incoming data. + * \brief Process received packet, prepare automatic response (e.g. ACK), pick incoming data. * - * \param relays Out: relays to be filled with message/connection details. - * \param msgs Packets received by knot_xdp_recv(). - * \param msg_count Number of received packets. + * \param relay Out: relay to be filled with message/connection details. + * \param msg Packet received by knot_xdp_recv(). * \param tcp_table Table of TCP connections. * \param syn_table Optional: extra table for handling partially established connections. * \param ignore Ignore specific TCP packets indication. * + * \note resulting relay might be knot_tcp_relay_empty() + * * \return KNOT_E* */ -int knot_tcp_recv(knot_tcp_relay_t *relays, knot_xdp_msg_t msgs[], uint32_t msg_count, +int knot_tcp_recv(knot_tcp_relay_t *relay, knot_xdp_msg_t *msg, knot_tcp_table_t *tcp_table, knot_tcp_table_t *syn_table, knot_tcp_ignore_t ignore); diff --git a/src/libknot/xdp/xdp.c b/src/libknot/xdp/xdp.c index 8286884..132f5c4 100644 --- a/src/libknot/xdp/xdp.c +++ b/src/libknot/xdp/xdp.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -38,63 +38,68 @@ #include "contrib/net.h" #define FRAME_SIZE 2048 - -#define FRAME_COUNT_TX 2048 -#define FRAME_COUNT_RX 2048 -#define FRAME_COUNT (FRAME_COUNT_TX + FRAME_COUNT_RX) - -#define RING_LEN_TX FRAME_COUNT_TX -#define RING_LEN_CQ FRAME_COUNT_TX -#define RING_LEN_RX FRAME_COUNT_RX -/* It's recommended that the FQ ring size >= HW RX ring size + AF_XDP RX ring size. */ -#define RING_LEN_FQ (2 * FRAME_COUNT_RX) - -#define ALLOC_RETRY_NUM 15 -#define ALLOC_RETRY_DELAY 20 // In nanoseconds. - -/* With recent compilers we statically check #defines for settings that - * get refused by AF_XDP drivers (in current versions, at least). */ -#if (__STDC_VERSION__ >= 201112L) -#define IS_POWER_OF_2(n) (((n) & (n - 1)) == 0) -_Static_assert((FRAME_SIZE == 4096 || FRAME_SIZE == 2048) - && IS_POWER_OF_2(RING_LEN_TX) && IS_POWER_OF_2(RING_LEN_RX) - && IS_POWER_OF_2(RING_LEN_CQ) && IS_POWER_OF_2(RING_LEN_FQ) - && FRAME_COUNT_TX <= (1 << 16) /* see tx_free_indices */ - , "Incorrect #define combination for AF_XDP."); -#endif +#define DEFAULT_RING_SIZE 2048 +#define RETRY_DELAY 20 // In nanoseconds. struct umem_frame { uint8_t bytes[FRAME_SIZE]; }; -static int configure_xsk_umem(struct kxsk_umem **out_umem, bool extra_frames) +static bool valid_config(const knot_xdp_config_t *config) +{ + if (FRAME_SIZE != 2048 && FRAME_SIZE != 4096) { + return false; + } + + if (config == NULL) { + return true; + } + + if ((config->ring_size & (config->ring_size - 1)) != 0) { + return false; + } + + return true; +} + +static uint32_t ring_size(const knot_xdp_config_t *config) +{ + return config != NULL ? config->ring_size : DEFAULT_RING_SIZE; +} + +static int configure_xsk_umem(struct kxsk_umem **out_umem, uint32_t ring_size) { /* Allocate memory and call driver to create the UMEM. */ struct kxsk_umem *umem = calloc(1, offsetof(struct kxsk_umem, tx_free_indices) - + sizeof(umem->tx_free_indices[0]) * FRAME_COUNT_TX); + + sizeof(umem->tx_free_indices[0]) * ring_size); if (umem == NULL) { return KNOT_ENOMEM; } + umem->ring_size = ring_size; - size_t frame_count = FRAME_COUNT + (extra_frames ? FRAME_COUNT_RX : 0); + /* It's recommended that the FQ ring size >= HW RX ring size + AF_XDP RX ring size. + * However, the performance is better if FQ size == AF_XDP RX size. */ + const uint32_t FQ_SIZE = umem->ring_size; + const uint32_t CQ_SIZE = umem->ring_size; + const uint32_t FRAMES = FQ_SIZE + CQ_SIZE; int ret = posix_memalign((void **)&umem->frames, getpagesize(), - FRAME_SIZE * frame_count); + FRAME_SIZE * FRAMES); if (ret != 0) { free(umem); return KNOT_ENOMEM; } - const struct xsk_umem_config config = { - .fill_size = RING_LEN_FQ, - .comp_size = RING_LEN_CQ, + const struct xsk_umem_config umem_config = { + .fill_size = FQ_SIZE, + .comp_size = CQ_SIZE, .frame_size = FRAME_SIZE, .frame_headroom = KNOT_XDP_PKT_ALIGNMENT, }; - ret = xsk_umem__create(&umem->umem, umem->frames, FRAME_SIZE * frame_count, - &umem->fq, &umem->cq, &config); + ret = xsk_umem__create(&umem->umem, umem->frames, FRAME_SIZE * FRAMES, + &umem->fq, &umem->cq, &umem_config); if (ret != KNOT_EOK) { free(umem->frames); free(umem); @@ -103,23 +108,23 @@ static int configure_xsk_umem(struct kxsk_umem **out_umem, bool extra_frames) *out_umem = umem; /* Designate the starting chunk of buffers for TX, and put them onto the stack. */ - umem->tx_free_count = FRAME_COUNT_TX; - for (uint32_t i = 0; i < FRAME_COUNT_TX; ++i) { + umem->tx_free_count = CQ_SIZE; + for (uint32_t i = 0; i < CQ_SIZE; ++i) { umem->tx_free_indices[i] = i; } /* Designate the rest of buffers for RX, and pass them to the driver. */ uint32_t idx = 0; - ret = xsk_ring_prod__reserve(&umem->fq, frame_count - FRAME_COUNT_TX, &idx); - if (ret != frame_count - FRAME_COUNT_TX) { + ret = xsk_ring_prod__reserve(&umem->fq, FQ_SIZE, &idx); + if (ret != FQ_SIZE) { assert(0); return KNOT_ERROR; } assert(idx == 0); - for (uint32_t i = FRAME_COUNT_TX; i < frame_count; ++i) { + for (uint32_t i = CQ_SIZE; i < CQ_SIZE + FQ_SIZE; ++i) { *xsk_ring_prod__fill_addr(&umem->fq, idx++) = i * FRAME_SIZE; } - xsk_ring_prod__submit(&umem->fq, frame_count - FRAME_COUNT_TX); + xsk_ring_prod__submit(&umem->fq, FQ_SIZE); return KNOT_EOK; } @@ -131,6 +136,33 @@ static void deconfigure_xsk_umem(struct kxsk_umem *umem) free(umem); } +static int enable_busypoll(int socket, unsigned timeout_us, unsigned budget) +{ +#if defined(SO_PREFER_BUSY_POLL) && defined(SO_BUSY_POLL_BUDGET) + int opt_val = 1; + if (setsockopt(socket, SOL_SOCKET, SO_PREFER_BUSY_POLL, + &opt_val, sizeof(opt_val)) != 0) { + return knot_map_errno(); + } + + opt_val = timeout_us; + if (setsockopt(socket, SOL_SOCKET, SO_BUSY_POLL, + &opt_val, sizeof(opt_val)) != 0) { + return knot_map_errno(); + } + + opt_val = budget; + if (setsockopt(socket, SOL_SOCKET, SO_BUSY_POLL_BUDGET, + &opt_val, sizeof(opt_val)) != 0) { + return knot_map_errno(); + } + + return KNOT_EOK; +#else + return KNOT_ENOTSUP; +#endif +} + static int configure_xsk_socket(struct kxsk_umem *umem, const struct kxsk_iface *iface, knot_xdp_socket_t **out_sock, @@ -143,14 +175,14 @@ static int configure_xsk_socket(struct kxsk_umem *umem, xsk_info->iface = iface; xsk_info->umem = umem; - uint16_t bind_flags = 0; + uint16_t bind_flags = XDP_USE_NEED_WAKEUP; if (config != NULL && config->force_copy) { bind_flags |= XDP_COPY; } const struct xsk_socket_config sock_conf = { - .tx_size = RING_LEN_TX, - .rx_size = RING_LEN_RX, + .tx_size = umem->ring_size, + .rx_size = umem->ring_size, .libbpf_flags = XSK_LIBBPF_FLAGS__INHIBIT_PROG_LOAD, .bind_flags = bind_flags, }; @@ -163,6 +195,17 @@ static int configure_xsk_socket(struct kxsk_umem *umem, return ret; } + if (config != NULL && config->busy_poll_budget > 0) { + ret = enable_busypoll(xsk_socket__fd(xsk_info->xsk), + config->busy_poll_timeout, config->busy_poll_budget); + if (ret != KNOT_EOK) { + xsk_socket__delete(xsk_info->xsk); + free(xsk_info); + return ret; + } + xsk_info->busy_poll = true; + } + *out_sock = xsk_info; return KNOT_EOK; } @@ -172,7 +215,7 @@ int knot_xdp_init(knot_xdp_socket_t **socket, const char *if_name, int if_queue, knot_xdp_filter_flag_t flags, uint16_t udp_port, uint16_t quic_port, knot_xdp_load_bpf_t load_bpf, const knot_xdp_config_t *xdp_config) { - if (socket == NULL || if_name == NULL || + if (socket == NULL || if_name == NULL || !valid_config(xdp_config) || (udp_port == quic_port && (flags & KNOT_XDP_FILTER_UDP) && (flags & KNOT_XDP_FILTER_QUIC)) || (flags & (KNOT_XDP_FILTER_UDP | KNOT_XDP_FILTER_TCP | KNOT_XDP_FILTER_QUIC)) == 0) { return KNOT_EINVAL; @@ -187,7 +230,7 @@ int knot_xdp_init(knot_xdp_socket_t **socket, const char *if_name, int if_queue, /* Initialize shared packet_buffer for umem usage. */ struct kxsk_umem *umem = NULL; - ret = configure_xsk_umem(&umem, xdp_config->extra_frames); + ret = configure_xsk_umem(&umem, ring_size(xdp_config)); if (ret != KNOT_EOK) { kxsk_iface_free(iface); return ret; @@ -266,7 +309,7 @@ static void tx_free_relative(struct kxsk_umem *umem, uint64_t addr_relative) { /* The address may not point to *start* of buffer, but `/` solves that. */ uint64_t index = addr_relative / FRAME_SIZE; - assert(index < FRAME_COUNT); + assert(index < umem->ring_size); umem->tx_free_indices[umem->tx_free_count++] = index; } @@ -285,7 +328,7 @@ void knot_xdp_send_prepare(knot_xdp_socket_t *socket) if (completed == 0) { return; } - assert(umem->tx_free_count + completed <= FRAME_COUNT_TX); + assert(umem->tx_free_count + completed <= umem->ring_size); for (uint32_t i = 0; i < completed; ++i) { uint64_t addr_relative = *xsk_ring_cons__comp_addr(cq, idx++); @@ -301,12 +344,13 @@ static struct umem_frame *alloc_tx_frame(knot_xdp_socket_t *socket) return malloc(sizeof(struct umem_frame)); } - const struct timespec delay = { .tv_nsec = ALLOC_RETRY_DELAY }; struct kxsk_umem *umem = socket->umem; - for (int i = 0; unlikely(umem->tx_free_count == 0); i++) { - if (i == ALLOC_RETRY_NUM) { - return NULL; + const struct timespec delay = { .tv_nsec = RETRY_DELAY }; + while (unlikely(umem->tx_free_count == 0)) { + if (socket->busy_poll || xsk_ring_prod__needs_wakeup(&socket->tx)) { + (void)sendto(xsk_socket__fd(socket->xsk), NULL, 0, + MSG_DONTWAIT, NULL, 0); } nanosleep(&delay, NULL); knot_xdp_send_prepare(socket); @@ -381,9 +425,7 @@ int knot_xdp_send(knot_xdp_socket_t *socket, const knot_xdp_msg_t msgs[], } if (unlikely(socket->send_mock != NULL)) { int ret = socket->send_mock(socket, msgs, count, sent); - for (uint32_t i = 0; i < count; ++i) { - free_unsent(socket, &msgs[i]); - } + knot_xdp_send_free(socket, msgs, count); return ret; } @@ -393,12 +435,13 @@ int knot_xdp_send(knot_xdp_socket_t *socket, const knot_xdp_msg_t msgs[], * and the API doesn't allow "cancelling reservations". * Therefore we handle `socket->tx.cached_prod` by hand. */ - if (xsk_prod_nb_free(&socket->tx, count) < count) { - /* This situation was sometimes observed in the emulated XDP mode. */ - for (uint32_t i = 0; i < count; ++i) { - free_unsent(socket, &msgs[i]); + const struct timespec delay = { .tv_nsec = RETRY_DELAY }; + while (unlikely(xsk_prod_nb_free(&socket->tx, count) < count)) { + if (socket->busy_poll || xsk_ring_prod__needs_wakeup(&socket->tx)) { + (void)sendto(xsk_socket__fd(socket->xsk), NULL, 0, + MSG_DONTWAIT, NULL, 0); } - return KNOT_ENOBUFS; + nanosleep(&delay, NULL); } uint32_t idx = socket->tx.cached_prod; @@ -425,7 +468,6 @@ int knot_xdp_send(knot_xdp_socket_t *socket, const knot_xdp_msg_t msgs[], assert(*sent <= count); socket->tx.cached_prod = idx; xsk_ring_prod__submit(&socket->tx, *sent); - socket->kernel_needs_wakeup = true; return KNOT_EOK; } @@ -446,34 +488,19 @@ int knot_xdp_send_finish(knot_xdp_socket_t *socket) return KNOT_EINVAL; } - /* Trigger sending queued packets. */ - if (!socket->kernel_needs_wakeup) { + if (!socket->busy_poll && !xsk_ring_prod__needs_wakeup(&socket->tx)) { return KNOT_EOK; } int ret = sendto(xsk_socket__fd(socket->xsk), NULL, 0, MSG_DONTWAIT, NULL, 0); - const bool is_ok = (ret >= 0); - // List of "safe" errors taken from - // https://github.com/torvalds/linux/blame/master/samples/bpf/xdpsock_user.c - const bool is_again = !is_ok && (errno == ENOBUFS || errno == EAGAIN - || errno == EBUSY || errno == ENETDOWN); - // Some of the !is_ok cases are a little unclear - what to do about the syscall, - // including how caller of _sendmsg_finish() should react. - if (is_ok || !is_again) { - socket->kernel_needs_wakeup = false; - } - if (is_again) { - return KNOT_EAGAIN; - } else if (is_ok) { + if (ret >= 0) { return KNOT_EOK; + } else if (errno == ENOBUFS || errno == EAGAIN || errno == EBUSY || + errno == ENETDOWN) { + return KNOT_EAGAIN; } else { return -errno; } - /* This syscall might be avoided with a newer kernel feature (>= 5.4): - https://www.kernel.org/doc/html/latest/networking/af_xdp.html#xdp-use-need-wakeup-bind-flag - Unfortunately it's not easy to continue supporting older kernels - when using this feature on newer ones. - */ } _public_ @@ -518,7 +545,7 @@ int knot_xdp_recv(knot_xdp_socket_t *socket, knot_xdp_msg_t msgs[], static uint8_t *msg_uframe_ptr(const knot_xdp_msg_t *msg) { - return NULL + ((msg->payload.iov_base - NULL) & ~(FRAME_SIZE - 1)); + return (uint8_t *)((uintptr_t)msg->payload.iov_base & ~(FRAME_SIZE - 1)); } _public_ @@ -529,30 +556,32 @@ void knot_xdp_recv_finish(knot_xdp_socket_t *socket, const knot_xdp_msg_t msgs[] return; } - const struct timespec delay = { .tv_nsec = ALLOC_RETRY_DELAY }; - struct kxsk_umem *const umem = socket->umem; struct xsk_ring_prod *const fq = &umem->fq; uint32_t idx = 0; - uint32_t reserved = xsk_ring_prod__reserve(fq, count, &idx); - for (int i = 0; unlikely(reserved < count); i++) { - if (i == ALLOC_RETRY_NUM) { - return; + const struct timespec delay = { .tv_nsec = RETRY_DELAY }; + while (unlikely(xsk_ring_prod__reserve(fq, count, &idx) != count)) { + if (socket->busy_poll || xsk_ring_prod__needs_wakeup(fq)) { + (void)recvfrom(xsk_socket__fd(socket->xsk), NULL, 0, + MSG_DONTWAIT, NULL, NULL); } nanosleep(&delay, NULL); - reserved = xsk_ring_prod__reserve(fq, count, &idx); } - for (uint32_t i = 0; i < reserved; ++i) { + for (uint32_t i = 0; i < count; ++i) { uint8_t *uframe_p = msg_uframe_ptr(&msgs[i]); uint64_t offset = uframe_p - umem->frames->bytes; *xsk_ring_prod__fill_addr(fq, idx++) = offset; } - xsk_ring_prod__submit(fq, reserved); + xsk_ring_prod__submit(fq, count); + // recvfrom() here slightly worsens the performance, poll is called later anyway. } +// The number of busy frames +#define RING_BUSY(ring) ((*(ring)->producer - *(ring)->consumer) & (ring)->mask) + _public_ void knot_xdp_socket_info(const knot_xdp_socket_t *socket, FILE *file) { @@ -560,10 +589,6 @@ void knot_xdp_socket_info(const knot_xdp_socket_t *socket, FILE *file) return; } - // The number of busy frames - #define RING_BUSY(ring) \ - ((*(ring)->producer - *(ring)->consumer) & (ring)->mask) - #define RING_PRINFO(name, ring) \ fprintf(file, "Ring %s: size %4d, busy %4d (prod %4d, cons %4d)\n", \ name, (unsigned)(ring)->size, \ @@ -571,11 +596,11 @@ void knot_xdp_socket_info(const knot_xdp_socket_t *socket, FILE *file) (unsigned)*(ring)->producer, (unsigned)*(ring)->consumer) const int rx_busyf = RING_BUSY(&socket->umem->fq) + RING_BUSY(&socket->rx); - fprintf(file, "\nLOST RX frames: %4d", (int)(FRAME_COUNT_RX - rx_busyf)); + fprintf(file, "\nLOST RX frames: %4d", (int)(socket->umem->ring_size - rx_busyf)); const int tx_busyf = RING_BUSY(&socket->umem->cq) + RING_BUSY(&socket->tx); const int tx_freef = socket->umem->tx_free_count; - fprintf(file, "\nLOST TX frames: %4d\n", (int)(FRAME_COUNT_TX - tx_busyf - tx_freef)); + fprintf(file, "\nLOST TX frames: %4d\n", (int)(socket->umem->ring_size - tx_busyf - tx_freef)); RING_PRINFO("FQ", &socket->umem->fq); RING_PRINFO("RX", &socket->rx); @@ -583,3 +608,39 @@ void knot_xdp_socket_info(const knot_xdp_socket_t *socket, FILE *file) RING_PRINFO("CQ", &socket->umem->cq); fprintf(file, "TX free frames: %4d\n", tx_freef); } + +_public_ +int knot_xdp_socket_stats(knot_xdp_socket_t *socket, knot_xdp_stats_t *stats) +{ + if (socket == NULL || stats == NULL) { + return KNOT_EINVAL; + } + + memset(stats, 0, sizeof(*stats)); + + stats->if_name = socket->iface->if_name; + stats->if_index = socket->iface->if_index; + stats->if_queue = socket->iface->if_queue; + + struct xdp_statistics xdp_stats; + socklen_t optlen = sizeof(xdp_stats); + + int fd = knot_xdp_socket_fd(socket); + int ret = getsockopt(fd, SOL_XDP, XDP_STATISTICS, &xdp_stats, &optlen); + if (ret != 0) { + return knot_map_errno(); + } else if (optlen != sizeof(xdp_stats)) { + return KNOT_EINVAL; + } + + size_t common_size = MIN(sizeof(xdp_stats), sizeof(stats->socket)); + memcpy(&stats->socket, &xdp_stats, common_size); + + stats->rings.tx_busy = socket->umem->ring_size - socket->umem->tx_free_count; + stats->rings.fq_fill = RING_BUSY(&socket->umem->fq); + stats->rings.rx_fill = RING_BUSY(&socket->rx); + stats->rings.tx_fill = RING_BUSY(&socket->tx); + stats->rings.cq_fill = RING_BUSY(&socket->umem->cq); + + return KNOT_EOK; +} diff --git a/src/libknot/xdp/xdp.h b/src/libknot/xdp/xdp.h index 6c8bb1e..5944d44 100644 --- a/src/libknot/xdp/xdp.h +++ b/src/libknot/xdp/xdp.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -53,14 +53,54 @@ typedef struct knot_xdp_socket knot_xdp_socket_t; /*! \brief Configuration of XDP socket. */ struct knot_xdp_config { - bool force_generic; /*!< Use generic XDP mode (avoid driver/hadrware implementation). */ - bool force_copy; /*!< Force copying packet data between kernel and user-space (avoid zero-copy). */ - bool extra_frames; /*!< Extra FQ frames. */ + uint16_t ring_size; /*!< Size of RX and TX rings (must be power of 2). */ + bool force_generic; /*!< Use generic XDP mode (avoid driver/hardware implementation). */ + bool force_copy; /*!< Force copying packet data between kernel and user-space (avoid zero-copy). */ + unsigned busy_poll_timeout; /*!< Preferred busy poll budget (0 means disabled). */ + unsigned busy_poll_budget; /*!< Preferred busy poll timeout (in microseconds) . */ }; /*! \brief Configuration of XDP socket. */ typedef struct knot_xdp_config knot_xdp_config_t; +/*! \brief Various statistics of an XDP socket (optimally kernel >=5.9). */ +typedef struct { + /*! Interface name. */ + const char *if_name; + /*! Interface name index (derived from ifname). */ + int if_index; + /*! Network card queue id. */ + unsigned if_queue; + /*! Counters (xdp_statistics) retrieved from the kernel via XDP_STATISTICS. */ + struct { + /*! Dropped for other reasons. */ + uint64_t rx_dropped; + /*! Dropped due to invalid descriptor. */ + uint64_t rx_invalid; + /*! Dropped due to invalid descriptor. */ + uint64_t tx_invalid; + /*! Dropped due to rx ring being full. */ + uint64_t rx_full; + /*! Failed to retrieve item from fill ring. */ + uint64_t fq_empty; + /*! Failed to retrieve item from tx ring. */ + uint64_t tx_empty; + } socket; + /*! States of rings of the XDP socket. */ + struct { + /*! Busy TX buffers. */ + uint16_t tx_busy; + /*! Free buffers to consume from FQ ring. */ + uint16_t fq_fill; + /*! Pending buffers in TX ring. */ + uint16_t rx_fill; + /*! Pending buffers in RX ring. */ + uint16_t tx_fill; + /*! Pending buffers in CQ ring. */ + uint16_t cq_fill; + } rings; +} knot_xdp_stats_t; + /*! * \brief Initialize XDP socket. * @@ -196,4 +236,14 @@ void knot_xdp_recv_finish(knot_xdp_socket_t *socket, const knot_xdp_msg_t msgs[] */ void knot_xdp_socket_info(const knot_xdp_socket_t *socket, FILE *file); +/*! + * \brief Gets various statistics of the XDP socket. + * + * \param socket XDP socket. + * \param stats Output structure. + * + * \return KNOT_E* + */ +int knot_xdp_socket_stats(knot_xdp_socket_t *socket, knot_xdp_stats_t *stats); + /*! @} */ diff --git a/src/libknot/yparser/ypschema.h b/src/libknot/yparser/ypschema.h index 57ced72..7fca93e 100644 --- a/src/libknot/yparser/ypschema.h +++ b/src/libknot/yparser/ypschema.h @@ -130,6 +130,8 @@ typedef union { int64_t dflt; /*! Possible unit type. */ yp_style_t unit; + /*! Alternative default value. */ + int64_t dflt_alt; } i; /*! Boolean variables. */ struct { diff --git a/src/libknot/yparser/yptrafo.c b/src/libknot/yparser/yptrafo.c index 60b3717..764a5d1 100644 --- a/src/libknot/yparser/yptrafo.c +++ b/src/libknot/yparser/yptrafo.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -31,25 +31,31 @@ #include "contrib/wire_ctx.h" enum { - UNIT_BYTE = 'B', - UNIT_KILO = 'K', - UNIT_MEGA = 'M', - UNIT_GIGA = 'G', - UNIT_SEC = 's', - UNIT_MIN = 'm', - UNIT_HOUR = 'h', - UNIT_DAY = 'd' + UNIT_BYTE = 'B', + UNIT_KILO = 'K', + UNIT_MEGA = 'M', + UNIT_GIGA = 'G', + UNIT_SEC = 's', + UNIT_MIN = 'm', + UNIT_HOUR = 'h', + UNIT_DAY = 'd', + UNIT_WEEK = 'w', + UNIT_MONTH = 'M', + UNIT_YEAR = 'y', }; enum { - MULTI_BYTE = 1, - MULTI_KILO = 1024, - MULTI_MEGA = 1024 * 1024, - MULTI_GIGA = 1024 * 1024 * 1024, - MULTI_SEC = 1, - MULTI_MIN = 60, - MULTI_HOUR = 3600, - MULTI_DAY = 24 * 3600 + MULTI_BYTE = 1, + MULTI_KILO = 1024, + MULTI_MEGA = 1024 * 1024, + MULTI_GIGA = 1024 * 1024 * 1024, + MULTI_SEC = 1, + MULTI_MIN = 60, + MULTI_HOUR = 3600, + MULTI_DAY = 24 * 3600, + MULTI_WEEK = MULTI_DAY * 7, + MULTI_MONTH = MULTI_DAY * 30, + MULTI_YEAR = MULTI_DAY * 365, }; static wire_ctx_t copy_in( @@ -186,6 +192,15 @@ static int remove_unit( case UNIT_DAY: multiplier = MULTI_DAY; break; + case UNIT_WEEK: + multiplier = MULTI_WEEK; + break; + case UNIT_MONTH: + multiplier = MULTI_MONTH; + break; + case UNIT_YEAR: + multiplier = MULTI_YEAR; + break; default: return KNOT_EINVAL; } @@ -295,9 +310,18 @@ static void add_unit( } else if (*number < MULTI_DAY) { multiplier = MULTI_HOUR; new_unit = UNIT_HOUR; - } else { + } else if (*number < MULTI_WEEK) { multiplier = MULTI_DAY; new_unit = UNIT_DAY; + } else if (*number < MULTI_MONTH) { + multiplier = MULTI_WEEK; + new_unit = UNIT_WEEK; + } else if (*number < MULTI_YEAR) { + multiplier = MULTI_MONTH; + new_unit = UNIT_MONTH; + } else { + multiplier = MULTI_YEAR; + new_unit = UNIT_YEAR; } } diff --git a/src/libzscanner/version.h b/src/libzscanner/version.h index f24b3a9..05ab471 100644 --- a/src/libzscanner/version.h +++ b/src/libzscanner/version.h @@ -17,8 +17,8 @@ #pragma once #define ZSCANNER_VERSION_MAJOR 3 -#define ZSCANNER_VERSION_MINOR 3 -#define ZSCANNER_VERSION_PATCH 0x09 +#define ZSCANNER_VERSION_MINOR 4 +#define ZSCANNER_VERSION_PATCH 0x00 #define ZSCANNER_VERSION_HEX ((ZSCANNER_VERSION_MAJOR << 16) | \ (ZSCANNER_VERSION_MINOR << 8) | \ diff --git a/src/utils/Makefile.inc b/src/utils/Makefile.inc index 3097050..1f11282 100644 --- a/src/utils/Makefile.inc +++ b/src/utils/Makefile.inc @@ -103,7 +103,11 @@ kxdpgun_SOURCES = \ utils/kxdpgun/ip_route.h \ utils/kxdpgun/load_queries.c \ utils/kxdpgun/load_queries.h \ - utils/kxdpgun/main.c + utils/kxdpgun/main.c \ + utils/kxdpgun/main.h \ + utils/kxdpgun/stats.c \ + utils/kxdpgun/stats.h + kxdpgun_CPPFLAGS = $(libknotus_la_CPPFLAGS) $(libmnl_CFLAGS) kxdpgun_LDADD = libknot.la $(libcontrib_LIBS) $(libmnl_LIBS) $(pthread_LIBS) diff --git a/src/utils/common/msg.h b/src/utils/common/msg.h index d2ed57e..fbd6c8e 100644 --- a/src/utils/common/msg.h +++ b/src/utils/common/msg.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -23,10 +23,10 @@ #define WARNING_ ";; WARNING: " #define DEBUG_ ";; DEBUG: " -#define ERR(msg, ...) { fprintf(stderr, ERROR_ msg "\n", ##__VA_ARGS__); fflush(stderr); } -#define INFO(msg, ...) { fprintf(stdout, INFO_ msg "\n", ##__VA_ARGS__); fflush(stdout); } -#define WARN(msg, ...) { fprintf(stderr, WARNING_ msg "\n", ##__VA_ARGS__); fflush(stderr); } -#define DBG(msg, ...) { msg_debug(DEBUG_ msg "\n", ##__VA_ARGS__); fflush(stdout); } +#define ERR(msg, ...) do { fprintf(stderr, ERROR_ msg "\n", ##__VA_ARGS__); fflush(stderr); } while (0) +#define INFO(msg, ...) do { fprintf(stdout, INFO_ msg "\n", ##__VA_ARGS__); fflush(stdout); } while (0) +#define WARN(msg, ...) do { fprintf(stderr, WARNING_ msg "\n", ##__VA_ARGS__); fflush(stderr); } while (0) +#define DBG(msg, ...) do { msg_debug(DEBUG_ msg "\n", ##__VA_ARGS__); fflush(stdout); } while (0) /*! \brief Enable/disable debugging. */ int msg_enable_debug(int val); @@ -37,6 +37,6 @@ int msg_debug(const char *fmt, ...); /*! \brief Debug message for null input. */ #define DBG_NULL DBG("%s: null parameter", __func__) -#define ERR2(msg, ...) { fprintf(stderr, "error: " msg "\n", ##__VA_ARGS__); fflush(stderr); } -#define WARN2(msg, ...) { fprintf(stderr, "warning: " msg "\n", ##__VA_ARGS__); fflush(stderr); } -#define INFO2(msg, ...) { fprintf(stdout, msg "\n", ##__VA_ARGS__); fflush(stdout); } +#define ERR2(msg, ...) do { fprintf(stderr, "error: " msg "\n", ##__VA_ARGS__); fflush(stderr); } while (0) +#define WARN2(msg, ...) do { fprintf(stderr, "warning: " msg "\n", ##__VA_ARGS__); fflush(stderr); } while (0) +#define INFO2(msg, ...) do { fprintf(stdout, msg "\n", ##__VA_ARGS__); fflush(stdout); } while (0) diff --git a/src/utils/common/netio.c b/src/utils/common/netio.c index eed14ee..8ea7b59 100644 --- a/src/utils/common/netio.c +++ b/src/utils/common/netio.c @@ -32,6 +32,7 @@ #include "utils/common/msg.h" #include "utils/common/tls.h" #include "libknot/libknot.h" +#include "libknot/quic/tls_common.h" #include "contrib/net.h" #include "contrib/proxyv2/proxyv2.h" #include "contrib/sockaddr.h" @@ -521,8 +522,8 @@ int net_connect(net_t *net) #endif //LIBNGHTTP2 { // Establish TLS connection. - ret = tls_ctx_setup_remote_endpoint(&net->tls, &dot_alpn, 1, NULL, - net_get_remote(net)); + ret = tls_ctx_setup_remote_endpoint(&net->tls, &dot_alpn, 1, + KNOT_TLS_PRIORITIES, net_get_remote(net)); if (ret != 0) { net_close(net); return ret; @@ -546,7 +547,7 @@ int net_connect(net_t *net) return ret; } ret = tls_ctx_setup_remote_endpoint(&net->tls, - &doq_alpn, 1, QUIC_PRIORITY, net_get_remote(net)); + &doq_alpn, 1, KNOT_TLS_PRIORITIES, net_get_remote(net)); if (ret != 0) { net_close(net); return ret; diff --git a/src/utils/common/params.c b/src/utils/common/params.c index d16af4c..fe5a854 100644 --- a/src/utils/common/params.c +++ b/src/utils/common/params.c @@ -21,7 +21,7 @@ #include <sys/socket.h> #ifdef LIBIDN -#include LIBIDN_HEADER +#include <idn2.h> #endif #include "utils/common/params.h" diff --git a/src/utils/common/params.h b/src/utils/common/params.h index 8b7565e..bb071aa 100644 --- a/src/utils/common/params.h +++ b/src/utils/common/params.h @@ -22,6 +22,7 @@ #include <stdio.h> #include "libknot/libknot.h" +#include "contrib/string.h" #include "contrib/ucw/lists.h" #define DEFAULT_IPV4_NAME "127.0.0.1" @@ -31,7 +32,7 @@ #define DEFAULT_DNS_QUIC_PORT "853" #define DEFAULT_DNS_TLS_PORT "853" #define DEFAULT_UDP_SIZE 512 -#define DEFAULT_EDNS_SIZE 4096 +#define DEFAULT_EDNS_SIZE 1232 #define MAX_PACKET_SIZE 65535 #define SEP_CHARS "\n\t " @@ -118,9 +119,15 @@ typedef struct { param_handle_f handler; } param_t; -inline static void print_version(const char *program_name) +inline static void print_version(const char *prog_name, bool verbose) { - printf("%s (Knot DNS), version %s\n", program_name, PACKAGE_VERSION); + if (prog_name != NULL) { + printf("%s, ", prog_name); + } + printf("Knot DNS %s\n", PACKAGE_VERSION); + if (verbose) { + printf("\n%s\n", configure_summary); + } } /*! diff --git a/src/utils/common/quic.h b/src/utils/common/quic.h index fd70d27..2b860c3 100644 --- a/src/utils/common/quic.h +++ b/src/utils/common/quic.h @@ -35,10 +35,6 @@ void quic_params_clean(quic_params_t *params); #include "utils/common/tls.h" -#define QUIC_DEFAULT_VERSION "-VERS-ALL:+VERS-TLS1.3" -#define QUIC_DEFAULT_GROUPS "-GROUP-ALL:+GROUP-X25519:+GROUP-SECP256R1:+GROUP-SECP384R1:+GROUP-SECP521R1" -#define QUIC_PRIORITY "%DISABLE_TLS13_COMPAT_MODE:NORMAL:"QUIC_DEFAULT_VERSION":"QUIC_DEFAULT_GROUPS - typedef enum { CLOSED, // Initialized CONNECTED, // RTT-0 diff --git a/src/utils/common/tls.c b/src/utils/common/tls.c index 276ae16..4c9a588 100644 --- a/src/utils/common/tls.c +++ b/src/utils/common/tls.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -398,7 +398,7 @@ int tls_certificate_verification(tls_ctx_t *ctx) }; size_t data_count = (ctx->params->hostname != NULL) ? 2 : 1; if (data_count == 1) { - WARN("TLS, no hostname provided, will not verify certificate owner") + WARN("TLS, no hostname provided, will not verify certificate owner"); } unsigned int status; @@ -533,7 +533,8 @@ int tls_ctx_setup_remote_endpoint(tls_ctx_t *ctx, const gnutls_datum_t *alpn, } if (priority != NULL) { - ret = gnutls_priority_set_direct(ctx->session, priority, NULL); + ret = gnutls_set_default_priority_append(ctx->session, priority, + NULL, 0); } else { ret = gnutls_set_default_priority(ctx->session); } diff --git a/src/utils/kcatalogprint/main.c b/src/utils/kcatalogprint/main.c index 0172347..85e50b6 100644 --- a/src/utils/kcatalogprint/main.c +++ b/src/utils/kcatalogprint/main.c @@ -108,7 +108,7 @@ int main(int argc, char *argv[]) { "catalog", required_argument, NULL, 'a' }, { "member", required_argument, NULL, 'm' }, { "help", no_argument, NULL, 'h' }, - { "version", no_argument, NULL, 'V' }, + { "version", optional_argument, NULL, 'V' }, { NULL } }; @@ -116,7 +116,7 @@ int main(int argc, char *argv[]) signal_init_std(); int opt = 0; - while ((opt = getopt_long(argc, argv, "c:C:D:a:m:hV", opts, NULL)) != -1) { + while ((opt = getopt_long(argc, argv, "c:C:D:a:m:hV::", opts, NULL)) != -1) { switch (opt) { case 'c': if (util_conf_init_file(optarg) != KNOT_EOK) { @@ -147,7 +147,7 @@ int main(int argc, char *argv[]) print_help(); goto success; case 'V': - print_version(PROGRAM_NAME); + print_version(PROGRAM_NAME, optarg != NULL); goto success; default: print_help(); @@ -155,13 +155,9 @@ int main(int argc, char *argv[]) } } - // Backward compatibility. if (argc - optind > 0) { - WARN2("obsolete parameter specified"); - if (util_conf_init_justdb("catalog-db", argv[optind]) != KNOT_EOK) { - goto failure; - } - optind++; + print_help(); + goto failure; } if (util_conf_init_default(true) != KNOT_EOK) { diff --git a/src/utils/kdig/kdig_params.c b/src/utils/kdig/kdig_params.c index c8fd83f..8566848 100644 --- a/src/utils/kdig/kdig_params.c +++ b/src/utils/kdig/kdig_params.c @@ -1690,7 +1690,7 @@ query_t *query_create(const char *owner, const query_t *conf) query->style.style.now = knot_time(); query->idn = true; query->nsid = false; - query->edns = -1; + query->edns = 0; query->cc.len = 0; query->sc.len = 0; query->badcookie = BADCOOKIE_RETRY_MAX; @@ -2517,12 +2517,7 @@ static int parse_opt1(const char *opt, const char *value, kdig_params_t *params, *index += add; break; case 'V': - if (len > 1) { - ERR("invalid option -%s", opt); - return KNOT_ENOTSUP; - } - - print_version(PROGRAM_NAME); + print_version(PROGRAM_NAME, len > 1); params->stop = true; break; case 'x': @@ -2598,8 +2593,8 @@ static int parse_opt1(const char *opt, const char *value, kdig_params_t *params, if (strcmp(opt, "-help") == 0) { print_help(); params->stop = true; - } else if (strcmp(opt, "-version") == 0) { - print_version(PROGRAM_NAME); + } else if (strncmp(opt, "-version", 8) == 0) { + print_version(PROGRAM_NAME, strlen(opt) > 9); params->stop = true; } else { ERR("invalid option: -%s", opt); diff --git a/src/utils/keymgr/bind_privkey.c b/src/utils/keymgr/bind_privkey.c index 9ab895c..bbb61a5 100644 --- a/src/utils/keymgr/bind_privkey.c +++ b/src/utils/keymgr/bind_privkey.c @@ -281,9 +281,7 @@ static int rsa_params_to_pem(const bind_privkey_t *params, dnssec_binary_t *pem) static gnutls_ecc_curve_t choose_ecdsa_curve(size_t pubkey_size) { switch (pubkey_size) { -#ifdef HAVE_ED25519 case 32: return GNUTLS_ECC_CURVE_ED25519; -#endif #ifdef HAVE_ED448 case 57: return GNUTLS_ECC_CURVE_ED448; #endif @@ -334,7 +332,6 @@ static int ecdsa_params_to_pem(dnssec_key_t *dnskey, const bind_privkey_t *param return dnssec_pem_from_x509(key, pem); } -#if defined(HAVE_ED25519) || defined(HAVE_ED448) static void eddsa_extract_public_params(dnssec_key_t *key, gnutls_ecc_curve_t *curve, gnutls_datum_t *x) { @@ -371,7 +368,6 @@ static int eddsa_params_to_pem(dnssec_key_t *dnskey, const bind_privkey_t *param return dnssec_pem_from_x509(key, pem); } -#endif int bind_privkey_to_pem(dnssec_key_t *key, bind_privkey_t *params, dnssec_binary_t *pem) { @@ -385,15 +381,11 @@ int bind_privkey_to_pem(dnssec_key_t *key, bind_privkey_t *params, dnssec_binary case DNSSEC_KEY_ALGORITHM_ECDSA_P256_SHA256: case DNSSEC_KEY_ALGORITHM_ECDSA_P384_SHA384: return ecdsa_params_to_pem(key, params, pem); -#ifdef HAVE_ED25519 case DNSSEC_KEY_ALGORITHM_ED25519: -#endif #ifdef HAVE_ED448 case DNSSEC_KEY_ALGORITHM_ED448: #endif -#if defined(HAVE_ED25519) || defined(HAVE_ED448) return eddsa_params_to_pem(key, params, pem); -#endif default: return DNSSEC_INVALID_KEY_ALGORITHM; } diff --git a/src/utils/keymgr/main.c b/src/utils/keymgr/main.c index b46aaa0..999b5c5 100644 --- a/src/utils/keymgr/main.c +++ b/src/utils/keymgr/main.c @@ -333,11 +333,10 @@ int main(int argc, char *argv[]) { "tsig", required_argument, NULL, 't' }, { "extended", no_argument, NULL, 'e' }, { "list", no_argument, NULL, 'l' }, - { "brief", no_argument, NULL, 'b' }, // Legacy. { "mono", no_argument, NULL, 'x' }, { "color", no_argument, NULL, 'X' }, { "help", no_argument, NULL, 'h' }, - { "version", no_argument, NULL, 'V' }, + { "version", optional_argument, NULL, 'V' }, { "json", no_argument, NULL, 'j' }, { NULL } }; @@ -358,7 +357,7 @@ int main(int argc, char *argv[]) list_params.color = isatty(STDOUT_FILENO); int opt = 0, parm = 0; - while ((opt = getopt_long(argc, argv, "c:C:D:t:ejlbxXhV", opts, NULL)) != -1) { + while ((opt = getopt_long(argc, argv, "c:C:D:t:ejlxXhV::", opts, NULL)) != -1) { switch (opt) { case 'c': if (util_conf_init_file(optarg) != KNOT_EOK) { @@ -394,9 +393,6 @@ int main(int argc, char *argv[]) case 'l': just_list = true; break; - case 'b': - WARN2("option '--brief' is deprecated and enabled by default"); - break; case 'x': list_params.color = false; break; @@ -407,7 +403,7 @@ int main(int argc, char *argv[]) print_help(); goto success; case 'V': - print_version(PROGRAM_NAME); + print_version(PROGRAM_NAME, optarg != NULL); goto success; default: print_help(); diff --git a/src/utils/keymgr/offline_ksk.c b/src/utils/keymgr/offline_ksk.c index b4260b9..05b2d2b 100644 --- a/src/utils/keymgr/offline_ksk.c +++ b/src/utils/keymgr/offline_ksk.c @@ -37,6 +37,8 @@ static int pregenerate_once(kdnssec_ctx_t *ctx, knot_time_t *next) { zone_sign_reschedule_t resch = { 0 }; + memset(ctx->stats, 0, sizeof(*ctx->stats)); + // generate ZSKs int ret = knot_dnssec_key_rollover(ctx, KEY_ROLL_ALLOW_ZSK_ROLL | KEY_ROLL_PRESERVE_FUTURE, &resch); if (ret != KNOT_EOK) { @@ -245,6 +247,9 @@ static int ksr_once(kdnssec_ctx_t *ctx, char **buf, size_t *buf_size, knot_time_ { knot_rrset_t *dnskey = NULL; zone_keyset_t keyset = { 0 }; + + memset(ctx->stats, 0, sizeof(*ctx->stats)); + int ret = load_dnskey_rrset(ctx, &dnskey, &keyset); if (ret != KNOT_EOK) { goto done; @@ -322,10 +327,10 @@ static int ksr_sign_dnskey(kdnssec_ctx_t *ctx, knot_rrset_t *zsk, knot_time_t no zone_keyset_t keyset = { 0 }; char *buf = NULL; size_t buf_size = 4096; - knot_time_t rrsigs_expire = 0; ctx->now = now; ctx->policy->dnskey_ttl = zsk->ttl; + memset(ctx->stats, 0, sizeof(*ctx->stats)); knot_timediff_t rrsig_refresh = ctx->policy->rrsig_refresh_before; if (rrsig_refresh == UINT32_MAX) { // not setting rrsig-refresh prohibited by documentation, but we need to do something @@ -352,7 +357,7 @@ static int ksr_sign_dnskey(kdnssec_ctx_t *ctx, knot_rrset_t *zsk, knot_time_t no // no check if the KSK used for signing (in keyset) is contained in DNSKEY record being signed (in KSR) ! for (int i = 0; i < keyset.count; i++) { - ret = key_records_sign(&keyset.keys[i], &r, ctx, &rrsigs_expire); + ret = key_records_sign(&keyset.keys[i], &r, ctx); if (ret != KNOT_EOK) { goto done; } @@ -362,7 +367,7 @@ static int ksr_sign_dnskey(kdnssec_ctx_t *ctx, knot_rrset_t *zsk, knot_time_t no print_header("SignedKeyResponse "KSR_SKR_VER, ctx->now, buf); *next_sign = knot_time_min( knot_get_next_zone_key_event(&keyset), - knot_time_add(rrsigs_expire, -rrsig_refresh) + knot_time_add(ctx->stats->expire, -rrsig_refresh) ); } @@ -446,6 +451,7 @@ static void skr_import_header(zs_scanner_t *sc) // trailing header without timestamp next_timestamp = 0; } + knot_time_t validity_ts = next_timestamp != 0 ? next_timestamp : ctx->timestamp; // delete possibly existing conflicting offline records ctx->ret = kasp_db_delete_offline_records( @@ -454,16 +460,11 @@ static void skr_import_header(zs_scanner_t *sc) // store previous SKR if (ctx->timestamp > 0 && ctx->ret == KNOT_EOK) { - ctx->ret = key_records_verify(&ctx->r, ctx->kctx, ctx->timestamp); + ctx->ret = key_records_verify(&ctx->r, ctx->kctx, ctx->timestamp, validity_ts); if (ctx->ret != KNOT_EOK) { return; } - if (next_timestamp > 0) { - ctx->ret = key_records_verify(&ctx->r, ctx->kctx, next_timestamp - 1); - if (ctx->ret != KNOT_EOK) { - return; - } - } + ctx->ret = kasp_db_store_offline_records(ctx->kctx->kasp_db, ctx->timestamp, &ctx->r); key_records_clear_rdatasets(&ctx->r); @@ -490,20 +491,14 @@ static void skr_validate_header(zs_scanner_t *sc) // trailing header without timestamp next_timestamp = 0; } + knot_time_t validity_ts = next_timestamp != 0 ? next_timestamp : ctx->timestamp; if (ctx->timestamp > 0 && ctx->ret == KNOT_EOK) { - int ret = key_records_verify(&ctx->r, ctx->kctx, ctx->timestamp); + int ret = key_records_verify(&ctx->r, ctx->kctx, ctx->timestamp, validity_ts); if (ret != KNOT_EOK) { // ctx->ret untouched ERR2("invalid SignedKeyResponse for %"KNOT_TIME_PRINTF" (%s)", ctx->timestamp, knot_strerror(ret)); } - if (next_timestamp > 0) { - ret = key_records_verify(&ctx->r, ctx->kctx, next_timestamp - 1); - if (ret != KNOT_EOK) { // ctx->ret untouched - ERR2("invalid SignedKeyResponse for %"KNOT_TIME_PRINTF" (%s)", - next_timestamp - 1, knot_strerror(ret)); - } - } key_records_clear_rdatasets(&ctx->r); } diff --git a/src/utils/khost/khost_params.c b/src/utils/khost/khost_params.c index 1423e09..de95d9b 100644 --- a/src/utils/khost/khost_params.c +++ b/src/utils/khost/khost_params.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -251,14 +251,14 @@ int khost_parse(kdig_params_t *params, int argc, char *argv[]) // Long options. struct option opts[] = { - { "help", no_argument, NULL, 'h' }, - { "version", no_argument, NULL, 'V' }, + { "help", no_argument, NULL, 'h' }, + { "version", optional_argument, NULL, 'V' }, { NULL } }; // Command line options processing. int opt = 0; - while ((opt = getopt_long(argc, argv, "46adhrsTvVwc:t:R:W:", opts, NULL)) + while ((opt = getopt_long(argc, argv, "46adhrsTvV::wc:t:R:W:", opts, NULL)) != -1) { switch (opt) { case '4': @@ -294,7 +294,7 @@ int khost_parse(kdig_params_t *params, int argc, char *argv[]) conf->style.show_footer = true; break; case 'V': - print_version(PROGRAM_NAME); + print_version(PROGRAM_NAME, optarg != NULL); params->stop = false; return KNOT_EOK; case 'w': diff --git a/src/utils/kjournalprint/main.c b/src/utils/kjournalprint/main.c index 3ba0019..1d633dd 100644 --- a/src/utils/kjournalprint/main.c +++ b/src/utils/kjournalprint/main.c @@ -342,11 +342,10 @@ int main(int argc, char *argv[]) { "zone-list", no_argument, NULL, 'z' }, { "check", no_argument, NULL, 'H' }, { "debug", no_argument, NULL, 'd' }, - { "no-color", no_argument, NULL, 'n' }, { "mono", no_argument, NULL, 'x' }, { "color", no_argument, NULL, 'X' }, { "help", no_argument, NULL, 'h' }, - { "version", no_argument, NULL, 'V' }, + { "version", optional_argument, NULL, 'V' }, { NULL } }; @@ -354,7 +353,7 @@ int main(int argc, char *argv[]) signal_init_std(); int opt = 0; - while ((opt = getopt_long(argc, argv, "c:C:D:l:s:zHdnxXhV", opts, NULL)) != -1) { + while ((opt = getopt_long(argc, argv, "c:C:D:l:s:zHdxXhV::", opts, NULL)) != -1) { switch (opt) { case 'c': if (util_conf_init_file(optarg) != KNOT_EOK) { @@ -393,7 +392,6 @@ int main(int argc, char *argv[]) case 'd': params.debug = true; break; - case 'n': case 'x': params.color = false; break; @@ -404,7 +402,7 @@ int main(int argc, char *argv[]) print_help(); goto success; case 'V': - print_version(PROGRAM_NAME); + print_version(PROGRAM_NAME, optarg != NULL); goto success; default: print_help(); @@ -412,15 +410,6 @@ int main(int argc, char *argv[]) } } - // Backward compatibility. - if ((justlist && (argc - optind > 0)) || (!justlist && (argc - optind > 1))) { - WARN2("obsolete parameter specified"); - if (util_conf_init_justdb("journal-db", argv[optind]) != KNOT_EOK) { - goto failure; - } - optind++; - } - signal_ctx.color = params.color; if (util_conf_init_default(true) != KNOT_EOK) { diff --git a/src/utils/knotc/commands.c b/src/utils/knotc/commands.c index c2c25a2..5cc1a14 100644 --- a/src/utils/knotc/commands.c +++ b/src/utils/knotc/commands.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -51,6 +51,7 @@ #define CMD_ZONE_BACKUP "zone-backup" #define CMD_ZONE_RESTORE "zone-restore" #define CMD_ZONE_SIGN "zone-sign" +#define CMD_ZONE_VALIDATE "zone-validate" #define CMD_ZONE_KEYS_LOAD "zone-keys-load" #define CMD_ZONE_KEY_ROLL "zone-key-rollover" #define CMD_ZONE_KSK_SBM "zone-ksk-submitted" @@ -99,7 +100,7 @@ static int check_args(cmd_args_t *args, int min, int max) { if (max == 0 && args->argc > 0) { - log_error("command doesn't take arguments"); + log_error("command does not take arguments"); return KNOT_EINVAL; } else if (min == max && args->argc != min) { log_error("command requires %i arguments", min); @@ -272,6 +273,7 @@ static void format_data(cmd_args_t *args, knot_ctl_type_t data_type, case CTL_ZONE_BACKUP: case CTL_ZONE_RESTORE: case CTL_ZONE_SIGN: + case CTL_ZONE_VALIDATE: case CTL_ZONE_KEYS_LOAD: case CTL_ZONE_KEY_ROLL: case CTL_ZONE_KSK_SBM: @@ -411,6 +413,7 @@ static void format_block(ctl_cmd_t cmd, bool failed, bool empty) case CTL_ZONE_BACKUP: case CTL_ZONE_RESTORE: case CTL_ZONE_SIGN: + case CTL_ZONE_VALIDATE: case CTL_ZONE_KEYS_LOAD: case CTL_ZONE_KEY_ROLL: case CTL_ZONE_KSK_SBM: @@ -1294,6 +1297,7 @@ const cmd_desc_t cmd_table[] = { { CMD_ZONE_BACKUP, cmd_zone_filter_ctl, CTL_ZONE_BACKUP, CMD_FOPT_ZONE }, { CMD_ZONE_RESTORE, cmd_zone_filter_ctl, CTL_ZONE_RESTORE, CMD_FOPT_ZONE }, { CMD_ZONE_SIGN, cmd_zone_ctl, CTL_ZONE_SIGN, CMD_FOPT_ZONE }, + { CMD_ZONE_VALIDATE, cmd_zone_ctl, CTL_ZONE_VALIDATE, CMD_FOPT_ZONE }, { CMD_ZONE_KEYS_LOAD, cmd_zone_ctl, CTL_ZONE_KEYS_LOAD, CMD_FOPT_ZONE }, { CMD_ZONE_KEY_ROLL, cmd_zone_key_roll_ctl, CTL_ZONE_KEY_ROLL, CMD_FREQ_ZONE }, { CMD_ZONE_KSK_SBM, cmd_zone_ctl, CTL_ZONE_KSK_SBM, CMD_FREQ_ZONE | CMD_FOPT_ZONE }, @@ -1347,6 +1351,7 @@ static const cmd_help_t cmd_help_table[] = { { CMD_ZONE_BACKUP, "[<zone>...] [<filter>...] +backupdir <dir>", "Backup zone data and metadata. (#)" }, { CMD_ZONE_RESTORE, "[<zone>...] [<filter>...] +backupdir <dir>", "Restore zone data and metadata. (#)" }, { CMD_ZONE_SIGN, "[<zone>...]", "Re-sign the automatically signed zone. (#)" }, + { CMD_ZONE_VALIDATE, "[<zone>...]", "Trigger a DNSSEC validation of the zone. (#)" }, { CMD_ZONE_KEYS_LOAD, "[<zone>...]", "Re-load keys from KASP database, sign the zone. (#)" }, { CMD_ZONE_KEY_ROLL, " <zone> ksk|zsk", "Trigger immediate key rollover. (#)" }, { CMD_ZONE_KSK_SBM, " <zone>...", "When KSK submission, confirm parent's DS presence. (#)" }, diff --git a/src/utils/knotc/main.c b/src/utils/knotc/main.c index dad3671..274ab6d 100644 --- a/src/utils/knotc/main.c +++ b/src/utils/knotc/main.c @@ -82,7 +82,7 @@ int main(int argc, char **argv) { "color", no_argument, NULL, 'X' }, { "verbose", no_argument, NULL, 'v' }, { "help", no_argument, NULL, 'h' }, - { "version", no_argument, NULL, 'V' }, + { "version", optional_argument, NULL, 'V' }, { NULL } }; @@ -97,7 +97,7 @@ int main(int argc, char **argv) /* Parse command line arguments */ int opt = 0; - while ((opt = getopt_long(argc, argv, "+c:C:m:s:t:befxXvhV", opts, NULL)) != -1) { + while ((opt = getopt_long(argc, argv, "+c:C:m:s:t:befxXvhV::", opts, NULL)) != -1) { switch (opt) { case 'c': params.orig_config = optarg; @@ -147,7 +147,7 @@ int main(int argc, char **argv) print_help(); return EXIT_SUCCESS; case 'V': - print_version(PROGRAM_NAME); + print_version(PROGRAM_NAME, optarg != NULL); return EXIT_SUCCESS; default: print_help(); diff --git a/src/utils/knotd/main.c b/src/utils/knotd/main.c index d4ebd53..e863296 100644 --- a/src/utils/knotd/main.c +++ b/src/utils/knotd/main.c @@ -38,15 +38,39 @@ #include "knot/conf/conf.h" #include "knot/conf/migration.h" #include "knot/conf/module.h" +#include "knot/common/dbus.h" #include "knot/common/log.h" #include "knot/common/process.h" #include "knot/common/stats.h" #include "knot/common/systemd.h" #include "knot/server/server.h" #include "knot/server/tcp-handler.h" +#include "utils/common/params.h" #define PROGRAM_NAME "knotd" +typedef enum { + CONCURRENT_EMPTY = 0, // fresh cctx without a thread. + CONCURRENT_ASSIGNED, // cctx assigned to process a command. + CONCURRENT_RUNNING, // ctl command is being processed in the thread. + CONCURRENT_IDLE, // command has been processed, waiting for a new one. + CONCURRENT_KILLED, // cctx cleanup has started. + CONCURRENT_FINISHED, // after having been killed, the thread is being joined. +} concurrent_ctl_state_t; + +typedef struct { + concurrent_ctl_state_t state; + pthread_mutex_t mutex; // Protects .state. + pthread_cond_t cond; + knot_ctl_t *ctl; + server_t *server; + pthread_t thread; + sigset_t sigmask; + int ret; + int thread_idx; + bool exclusive; +} concurrent_ctl_ctx_t; + /* Signal flags. */ static volatile bool sig_req_stop = false; static volatile bool sig_req_reload = false; @@ -161,13 +185,14 @@ static void setup_signals(void) sigdelset(&all, SIGBUS); sigdelset(&all, SIGFPE); sigdelset(&all, SIGSEGV); - pthread_sigmask(SIG_SETMASK, &all, NULL); /* Setup handlers. */ struct sigaction action = { .sa_handler = handle_signal }; for (const struct signal *s = SIGNALS; s->signum > 0; s++) { sigaction(s->signum, &action, NULL); } + + pthread_sigmask(SIG_SETMASK, &all, NULL); } /*! \brief Unblock server control signals. */ @@ -185,6 +210,24 @@ static void enable_signals(void) pthread_sigmask(SIG_UNBLOCK, &mask, NULL); } +/*! \brief Create a control thread with correct signals setting. */ +static void create_thread_sigmask(pthread_t *thr, void *(*fcn)(void*), void *ctx, + sigset_t *out_mask) +{ + /* Block all blockable signals. */ + sigset_t mask; + sigfillset(&mask); + sigdelset(&mask, SIGBUS); + sigdelset(&mask, SIGFPE); + sigdelset(&mask, SIGILL); + sigdelset(&mask, SIGSEGV); + pthread_sigmask(SIG_SETMASK, &mask, out_mask); + + pthread_create(thr, NULL, fcn, ctx); + + pthread_sigmask(SIG_SETMASK, out_mask, NULL); +} + /*! \brief Drop POSIX 1003.1e capabilities. */ static void drop_capabilities(void) { @@ -224,6 +267,7 @@ static void check_loaded(server_t *server) return; } + rcu_read_lock(); knot_zonedb_iter_t *it = knot_zonedb_iter_begin(server->zone_db); while (!knot_zonedb_iter_finished(it)) { zone_t *zone = (zone_t *)knot_zonedb_iter_val(it); @@ -234,9 +278,162 @@ static void check_loaded(server_t *server) knot_zonedb_iter_next(it); } knot_zonedb_iter_free(it); + rcu_read_unlock(); finished = true; - systemd_emit_running(true); + dbus_emit_running(true); +} + +static void *ctl_process_thread(void *arg); + +/*! + * Try to find an empty ctl processing context and if successful, + * prepare to lauch the incomming command processing in it. + * + * \param[in] concurrent_ctxs Configured concurrent control contexts. + * \param[in] n_ctxs Number of configured concurrent control contexts. + * \param[in] ctl Control context. + * + * \return Assigned concurrent control context, or NULL. + */ + +static concurrent_ctl_ctx_t *find_free_ctx(concurrent_ctl_ctx_t *concurrent_ctxs, + size_t n_ctxs, knot_ctl_t *ctl) +{ + concurrent_ctl_ctx_t *res = NULL; + for (size_t i = 0; i < n_ctxs && res == NULL; i++) { + concurrent_ctl_ctx_t *cctx = &concurrent_ctxs[i]; + pthread_mutex_lock(&cctx->mutex); + if (cctx->exclusive) { + while (cctx->state != CONCURRENT_IDLE) { + pthread_cond_wait(&cctx->cond, &cctx->mutex); + } + knot_ctl_free(cctx->ctl); + cctx->ctl = knot_ctl_clone(ctl); + if (cctx->ctl == NULL) { + cctx->exclusive = false; + pthread_mutex_unlock(&cctx->mutex); + break; + } + cctx->state = CONCURRENT_ASSIGNED; + res = cctx; + pthread_cond_broadcast(&cctx->cond); + } + pthread_mutex_unlock(&cctx->mutex); + } + for (size_t i = 0; i < n_ctxs && res == NULL; i++) { + concurrent_ctl_ctx_t *cctx = &concurrent_ctxs[i]; + pthread_mutex_lock(&cctx->mutex); + switch (cctx->state) { + case CONCURRENT_EMPTY: + create_thread_sigmask(&cctx->thread, ctl_process_thread, cctx, &cctx->sigmask); + break; + case CONCURRENT_IDLE: + knot_ctl_free(cctx->ctl); + pthread_cond_broadcast(&cctx->cond); + break; + default: + pthread_mutex_unlock(&cctx->mutex); + continue; + } + cctx->ctl = knot_ctl_clone(ctl); + if (cctx->ctl != NULL) { + cctx->state = CONCURRENT_ASSIGNED; + res = cctx; + } + pthread_mutex_unlock(&cctx->mutex); + } + return res; +} + +static void init_ctxs(concurrent_ctl_ctx_t *concurrent_ctxs, size_t n_ctxs, server_t *server) +{ + for (size_t i = 0; i < n_ctxs; i++) { + concurrent_ctl_ctx_t *cctx = &concurrent_ctxs[i]; + pthread_mutex_init(&cctx->mutex, NULL); + pthread_cond_init(&cctx->cond, NULL); + cctx->server = server; + cctx->thread_idx = i + 1; + } +} + +static int cleanup_ctxs(concurrent_ctl_ctx_t *concurrent_ctxs, size_t n_ctxs) +{ + int ret = KNOT_EOK; + for (size_t i = 0; i < n_ctxs; i++) { + concurrent_ctl_ctx_t *cctx = &concurrent_ctxs[i]; + pthread_mutex_lock(&cctx->mutex); + if (cctx->state == CONCURRENT_IDLE) { + knot_ctl_free(cctx->ctl); + cctx->ctl = NULL; + if (cctx->ret == KNOT_CTL_ESTOP) { + ret = cctx->ret; + } + } + pthread_mutex_unlock(&cctx->mutex); + } + return ret; +} + +static void finalize_ctxs(concurrent_ctl_ctx_t *concurrent_ctxs, size_t n_ctxs) +{ + for (size_t i = 0; i < n_ctxs; i++) { + concurrent_ctl_ctx_t *cctx = &concurrent_ctxs[i]; + pthread_mutex_lock(&cctx->mutex); + if (cctx->state == CONCURRENT_EMPTY) { + pthread_mutex_unlock(&cctx->mutex); + pthread_mutex_destroy(&cctx->mutex); + pthread_cond_destroy(&cctx->cond); + continue; + } + + cctx->state = CONCURRENT_KILLED; + pthread_cond_broadcast(&cctx->cond); + pthread_mutex_unlock(&cctx->mutex); + (void)pthread_join(cctx->thread, NULL); + + assert(cctx->state == CONCURRENT_FINISHED); + knot_ctl_free(cctx->ctl); + pthread_mutex_destroy(&cctx->mutex); + pthread_cond_destroy(&cctx->cond); + } +} + +static void *ctl_process_thread(void *arg) +{ + concurrent_ctl_ctx_t *ctx = arg; + rcu_register_thread(); + setup_signals(); // in fact, this blocks common signals so that they + // arrive to main thread instead of this one + + pthread_mutex_lock(&ctx->mutex); + while (ctx->state != CONCURRENT_KILLED) { + if (ctx->state != CONCURRENT_ASSIGNED) { + pthread_cond_wait(&ctx->cond, &ctx->mutex); + continue; + } + ctx->state = CONCURRENT_RUNNING; + bool exclusive = ctx->exclusive; + pthread_mutex_unlock(&ctx->mutex); + + // Not IDLE, ctx can be read without locking. + int ret = ctl_process(ctx->ctl, ctx->server, ctx->thread_idx, &exclusive); + + pthread_mutex_lock(&ctx->mutex); + ctx->ret = ret; + ctx->exclusive = exclusive; + if (ctx->state == CONCURRENT_RUNNING) { // not KILLED + ctx->state = CONCURRENT_IDLE; + pthread_cond_broadcast(&ctx->cond); + } + } + + knot_ctl_close(ctx->ctl); + + ctx->state = CONCURRENT_FINISHED; + pthread_mutex_unlock(&ctx->mutex); + rcu_unregister_thread(); + return NULL; } /*! \brief Event loop listening for signals and remote commands. */ @@ -274,7 +471,7 @@ static void event_loop(server_t *server, const char *socket, bool daemonize, /* Bind the control socket. */ uint16_t backlog = conf_get_int(conf(), C_CTL, C_BACKLOG); - int ret = knot_ctl_bind2(ctl, listen, backlog); + int ret = knot_ctl_bind(ctl, listen, backlog); if (ret != KNOT_EOK) { knot_ctl_free(ctl); log_fatal("control, failed to bind socket '%s' (%s)", @@ -286,6 +483,10 @@ static void event_loop(server_t *server, const char *socket, bool daemonize, enable_signals(); + concurrent_ctl_ctx_t concurrent_ctxs[CTL_MAX_CONCURRENT] = { 0 }; + init_ctxs(concurrent_ctxs, CTL_MAX_CONCURRENT, server); + bool main_thread_exclusive = false; + /* Notify systemd about successful start. */ systemd_ready_notify(); if (daemonize) { @@ -299,15 +500,19 @@ static void event_loop(server_t *server, const char *socket, bool daemonize, /* Interrupts. */ if (sig_req_reload && !sig_req_stop) { sig_req_reload = false; + pthread_rwlock_wrlock(&server->ctl_lock); server_reload(server, RELOAD_FULL); + pthread_rwlock_unlock(&server->ctl_lock); } if (sig_req_zones_reload && !sig_req_stop) { sig_req_zones_reload = false; reload_t mode = server->catalog_upd_signal ? RELOAD_CATALOG : RELOAD_ZONES; + pthread_rwlock_wrlock(&server->ctl_lock); server->catalog_upd_signal = false; server_update_zones(conf(), server, mode); + pthread_rwlock_unlock(&server->ctl_lock); } - if (sig_req_stop) { + if (sig_req_stop || cleanup_ctxs(concurrent_ctxs, CTL_MAX_CONCURRENT) == KNOT_CTL_ESTOP) { break; } @@ -325,15 +530,20 @@ static void event_loop(server_t *server, const char *socket, bool daemonize, continue; } - ret = ctl_process(ctl, server); - knot_ctl_close(ctl); - if (ret == KNOT_CTL_ESTOP) { - break; + if (main_thread_exclusive || + find_free_ctx(concurrent_ctxs, CTL_MAX_CONCURRENT, ctl) == NULL) { + ret = ctl_process(ctl, server, 0, &main_thread_exclusive); + knot_ctl_close(ctl); + if (ret == KNOT_CTL_ESTOP) { + break; + } } } + finalize_ctxs(concurrent_ctxs, CTL_MAX_CONCURRENT); + if (conf()->cache.srv_dbus_event & DBUS_EVENT_RUNNING) { - systemd_emit_running(false); + dbus_emit_running(false); } /* Unbind the control socket. */ @@ -363,11 +573,6 @@ static void print_help(void) CONF_MAPSIZE, RUN_DIR "/knot.sock"); } -static void print_version(void) -{ - printf("%s (Knot DNS), version %s\n", PROGRAM_NAME, PACKAGE_VERSION); -} - static int set_config(const char *confdb, const char *config, size_t max_conf_size) { if (config != NULL && confdb != NULL) { @@ -440,7 +645,7 @@ int main(int argc, char **argv) { "daemonize", optional_argument, NULL, 'd' }, { "verbose", no_argument, NULL, 'v' }, { "help", no_argument, NULL, 'h' }, - { "version", no_argument, NULL, 'V' }, + { "version", optional_argument, NULL, 'V' }, { NULL } }; @@ -449,7 +654,7 @@ int main(int argc, char **argv) /* Parse command line arguments. */ int opt = 0; - while ((opt = getopt_long(argc, argv, "c:C:m:s:dvhV", opts, NULL)) != -1) { + while ((opt = getopt_long(argc, argv, "c:C:m:s:dvhV::", opts, NULL)) != -1) { switch (opt) { case 'c': config = optarg; @@ -481,7 +686,7 @@ int main(int argc, char **argv) print_help(); return EXIT_SUCCESS; case 'V': - print_version(); + print_version(PROGRAM_NAME, optarg != NULL); return EXIT_SUCCESS; default: print_help(); @@ -570,14 +775,9 @@ int main(int argc, char **argv) return EXIT_FAILURE; } - if (conf()->cache.srv_dbus_event != DBUS_EVENT_NONE) { - ret = systemd_dbus_open(); - if (ret != KNOT_EOK) { - log_error("d-bus: failed to open system bus (%s)", - knot_strerror(ret)); - } else { - log_info("d-bus: connected to system bus"); - } + /* Connect to the system D-bus. */ + if (conf()->cache.srv_dbus_event != DBUS_EVENT_NONE && + dbus_open() == KNOT_EOK) { int64_t delay = conf_get_int(conf(), C_SRV, C_DBUS_INIT_DELAY); sleep(delay); } @@ -595,7 +795,7 @@ int main(int argc, char **argv) server_wait(&server); server_deinit(&server); conf_free(conf()); - systemd_dbus_close(); + dbus_close(); log_close(); dnssec_crypto_cleanup(); return EXIT_FAILURE; @@ -636,7 +836,7 @@ int main(int argc, char **argv) rcu_unregister_thread(); pid_cleanup(); conf_free(conf()); - systemd_dbus_close(); + dbus_close(); log_close(); dnssec_crypto_cleanup(); return EXIT_FAILURE; @@ -660,7 +860,7 @@ int main(int argc, char **argv) /* Unhook from RCU. */ rcu_unregister_thread(); - systemd_dbus_close(); + dbus_close(); log_info("shutting down"); log_close(); diff --git a/src/utils/knsec3hash/knsec3hash.c b/src/utils/knsec3hash/knsec3hash.c index a7bac97..a18498d 100644 --- a/src/utils/knsec3hash/knsec3hash.c +++ b/src/utils/knsec3hash/knsec3hash.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -36,7 +36,7 @@ */ static void print_help(void) { - printf("Usage: " PROGRAM_NAME " <salt> <algorithm> <iterations> <domain-name>\n"); + printf("Usage: " PROGRAM_NAME " [-h | -V] <salt> <algorithm> <iterations> <domain-name>\n"); printf("Example: " PROGRAM_NAME " c01dcafe 1 10 knot-dns.cz\n"); printf("Alternative usage: "PROGRAM_NAME " <algorithm> <flags> <iterations> <salt> <domain-name>\n"); printf("Example: " PROGRAM_NAME " 1 0 10 c01dcafe knot-dns.cz\n"); @@ -103,19 +103,19 @@ static bool parse_nsec3_params(dnssec_nsec3_params_t *params, const char *salt_s int main(int argc, char *argv[]) { struct option options[] = { - { "help", no_argument, NULL, 'h' }, - { "version", no_argument, NULL, 'V' }, + { "help", no_argument, NULL, 'h' }, + { "version", optional_argument, NULL, 'V' }, { NULL } }; int opt = 0; - while ((opt = getopt_long(argc, argv, "hV", options, NULL)) != -1) { + while ((opt = getopt_long(argc, argv, "hV::", options, NULL)) != -1) { switch(opt) { case 'h': print_help(); return EXIT_SUCCESS; case 'V': - print_version(PROGRAM_NAME); + print_version(PROGRAM_NAME, optarg != NULL); return EXIT_SUCCESS; default: print_help(); diff --git a/src/utils/knsupdate/knsupdate_exec.c b/src/utils/knsupdate/knsupdate_exec.c index e201711..d716ffb 100644 --- a/src/utils/knsupdate/knsupdate_exec.c +++ b/src/utils/knsupdate/knsupdate_exec.c @@ -452,15 +452,23 @@ static int pkt_sendrecv(knsupdate_params_t *params) return -1; } + ret = net_init_crypto(&net, ¶ms->tls_params, NULL, ¶ms->quic_params); + if (ret != 0) { + ERR("failed to initialize crypto context (%s)", knot_strerror(ret)); + net_clean(&net); + return -1; + } + ret = net_connect(&net); - DBG("%s: send_msg = %d", __func__, net.sockfd); if (ret != KNOT_EOK) { + ERR("failed to connect (%s)", knot_strerror(ret)); net_clean(&net); return -1; } ret = net_send(&net, params->query->wire, params->query->size); if (ret != KNOT_EOK) { + ERR("failed to send update (%s)", knot_strerror(ret)); net_close(&net); net_clean(&net); return -1; @@ -471,8 +479,8 @@ static int pkt_sendrecv(knsupdate_params_t *params) /* Wait for reception. */ int rb = net_receive(&net, params->answer->wire, params->answer->max_size); - DBG("%s: receive_msg = %d", __func__, rb); if (rb <= 0) { + ERR("failed to receive response (%s)", knot_strerror(rb)); net_close(&net); net_clean(&net); return -1; diff --git a/src/utils/knsupdate/knsupdate_params.c b/src/utils/knsupdate/knsupdate_params.c index f9fa41f..5aaf808 100644 --- a/src/utils/knsupdate/knsupdate_params.c +++ b/src/utils/knsupdate/knsupdate_params.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -26,6 +26,7 @@ #include "utils/common/netio.h" #include "libknot/libknot.h" #include "libknot/tsig.h" +#include "contrib/base64.h" #include "contrib/mempattern.h" #include "contrib/strtonum.h" #include "contrib/ucw/mempool.h" @@ -90,6 +91,8 @@ static int knsupdate_init(knsupdate_params_t *params) init_list(¶ms->update_list); init_list(¶ms->prereq_list); + tls_params_init(¶ms->tls_params); + /* Initialize memory context. */ mm_ctx_mempool(¶ms->mm, MM_DEFAULT_BLKSIZE); @@ -142,6 +145,9 @@ void knsupdate_clean(knsupdate_params_t *params) knot_pkt_free(params->answer); knot_tsig_key_deinit(¶ms->tsig_key); + tls_params_clean(¶ms->tls_params); + quic_params_clean(¶ms->quic_params); + /* Clean up the structure. */ mp_delete(params->mm.ctx); memset(params, 0, sizeof(*params)); @@ -172,9 +178,31 @@ void knsupdate_reset(knsupdate_params_t *params) static void print_help(void) { - printf("Usage: %s [-d] [-v] [-k keyfile | -y [hmac:]name:key]\n" - " [-p port] [-t timeout] [-r retries] [filename]\n", - PROGRAM_NAME); + printf("Usage:\n" + " %s [-T] [options] [filename]\n" + " %s [-S | -Q] [tls_options] [options] [filename]\n" + "\n" + "Options:\n" + " -T, --tcp Use TCP protocol.\n" + " -S, --tls Use TLS protocol.\n" + " -Q, --quic Use QUIC protocol.\n" + " -p, --port <num> Remote port.\n" + " -r, --retry <num> Number of retries over UDP.\n" + " -t, --timeout <num> Update timeout.\n" + " -y, --tsig <str> TSIG key in the form [alg:]name:key.\n" + " -k, --tsigfile <path> Path to a TSIG key file.\n" + " -d, --debug Debug mode output.\n" + " -h, --help Print the program help.\n" + " -V, --version Print the program version.\n" + "\n" + "QUIC/TLS options:\n" + " -H, --hostname <str> Remote hostname validation.\n" + " -P, --pin <base64> Certificate key PIN.\n" + " -A, --ca [<path>] Path to a CA file.\n" + " -E, --certfile <path> Path to a client certificate file.\n" + " -K, --keyfile <path> Path to a client key file.\n" + " -s, --sni <str> Remote SNI.\n", + PROGRAM_NAME, PROGRAM_NAME); } int knsupdate_parse(knsupdate_params_t *params, int argc, char *argv[]) @@ -188,40 +216,74 @@ int knsupdate_parse(knsupdate_params_t *params, int argc, char *argv[]) return ret; } - // Long options. + const char *opts_str = "dhvTSQV::p:r:t:y:k:H:P:A::E:K:s:"; struct option opts[] = { - { "help", no_argument, NULL, 'h' }, - { "version", no_argument, NULL, 'V' }, + { "debug", no_argument, NULL, 'd' }, + { "help", no_argument, NULL, 'h' }, + { "tcp", no_argument, NULL, 'T' }, + { "tls", no_argument, NULL, 'S' }, + { "quic", no_argument, NULL, 'Q' }, + { "version", optional_argument, NULL, 'V' }, + { "port", required_argument, NULL, 'p' }, + { "retry", required_argument, NULL, 'r' }, + { "timeout", required_argument, NULL, 't' }, + { "tsig", required_argument, NULL, 'y' }, + { "tsigfile", required_argument, NULL, 'k' }, + { "hostname", required_argument, NULL, 'H' }, + { "pin", required_argument, NULL, 'P' }, + { "ca", optional_argument, NULL, 'A' }, + { "certfile", required_argument, NULL, 'E' }, + { "keyfile", required_argument, NULL, 'K' }, + { "sni", required_argument, NULL, 's' }, { NULL } }; - /* Command line options processing. */ + bool default_port = true; + int opt = 0; - while ((opt = getopt_long(argc, argv, "dhDvVp:t:r:y:k:", opts, NULL)) - != -1) { + while ((opt = getopt_long(argc, argv, opts_str, opts, NULL)) != -1) { switch (opt) { case 'd': - case 'D': /* Extra debugging. */ msg_enable_debug(1); break; case 'h': print_help(); params->stop = true; return KNOT_EOK; - case 'v': + case 'v': // Compatibility with nsupdate. + case 'T': params->protocol = PROTO_TCP; break; + case 'S': + params->protocol = PROTO_TCP; + + params->tls_params.enable = true; + + if (default_port) { + free(params->server->service); + params->server->service = strdup(DEFAULT_DNS_TLS_PORT); + } + break; + case 'Q': + params->protocol = PROTO_UDP; + + params->tls_params.enable = true; + params->quic_params.enable = true; + + if (default_port) { + free(params->server->service); + params->server->service = strdup(DEFAULT_DNS_QUIC_PORT); + } + break; case 'V': - print_version(PROGRAM_NAME); + print_version(PROGRAM_NAME, optarg != NULL); params->stop = true; return KNOT_EOK; case 'p': + assert(optarg); + default_port = false; free(params->server->service); params->server->service = strdup(optarg); - if (!params->server->service) { - ERR("failed to set default port '%s'", optarg); - return KNOT_ENOMEM; - } break; case 'r': ret = str_to_u32(optarg, ¶ms->retries); @@ -241,7 +303,7 @@ int knsupdate_parse(knsupdate_params_t *params, int argc, char *argv[]) knot_tsig_key_deinit(¶ms->tsig_key); ret = knot_tsig_key_init_str(¶ms->tsig_key, optarg); if (ret != KNOT_EOK) { - ERR("failed to parse key '%s'", optarg); + ERR("failed to parse TSIG key '%s'", optarg); return ret; } break; @@ -249,9 +311,63 @@ int knsupdate_parse(knsupdate_params_t *params, int argc, char *argv[]) knot_tsig_key_deinit(¶ms->tsig_key); ret = knot_tsig_key_init_file(¶ms->tsig_key, optarg); if (ret != KNOT_EOK) { - ERR("failed to parse keyfile '%s'", optarg); + ERR("failed to parse TSIG keyfile '%s'", optarg); + return ret; + } + break; + case 'H': + assert(optarg); + free(params->tls_params.hostname); + params->tls_params.hostname = strdup(optarg); + break; + case 'P': + assert(optarg); + uint8_t pin[64] = { 0 }; + ret = knot_base64_decode((const uint8_t *)optarg, strlen(optarg), pin, sizeof(pin)); + if (ret < 0) { + ERR("invalid certificate pin %s", optarg); return ret; + } else if (ret != CERT_PIN_LEN) { // Check for 256-bit value. + ERR("invalid SHA256 hash length of certificate pin %s", optarg); + return KNOT_EINVAL; } + + uint8_t *item = malloc(1 + ret); // 1 ~ leading data length. + if (item == NULL) { + return KNOT_ENOMEM; + } + item[0] = ret; + memcpy(&item[1], pin, ret); + + if (ptrlist_add(¶ms->tls_params.pins, item, NULL) == NULL) { + return KNOT_ENOMEM; + } + + break; + case 'A': + if (optarg == NULL) { + params->tls_params.system_ca = true; + break; + } + if (ptrlist_add(¶ms->tls_params.ca_files, strdup(optarg), NULL) == NULL) { + ERR("failed to set CA file '%s'", optarg); + return KNOT_ENOMEM; + } + break; + case 'E': + assert(optarg); + free(params->tls_params.certfile); + params->tls_params.certfile = strdup(optarg); + break; + case 'K': + assert(optarg); + free(params->tls_params.keyfile); + params->tls_params.keyfile = strdup(optarg); + break; + case 's': + assert(optarg); + free(params->tls_params.sni); + params->tls_params.sni = strdup(optarg); break; default: print_help(); @@ -259,8 +375,8 @@ int knsupdate_parse(knsupdate_params_t *params, int argc, char *argv[]) } } - /* No retries for TCP. */ - if (params->protocol == PROTO_TCP) { + /* Retries only for UDP. */ + if (params->protocol == PROTO_TCP || params->quic_params.enable) { params->retries = 0; } else { /* If wait/tries < 1 s, set 1 second for each try. */ @@ -277,7 +393,7 @@ int knsupdate_parse(knsupdate_params_t *params, int argc, char *argv[]) ptrlist_add(¶ms->qfiles, argv[optind], ¶ms->mm); } - return ret; + return KNOT_EOK; } int knsupdate_set_ttl(knsupdate_params_t *params, const uint32_t ttl) diff --git a/src/utils/knsupdate/knsupdate_params.h b/src/utils/knsupdate/knsupdate_params.h index 1933244..fbf30e5 100644 --- a/src/utils/knsupdate/knsupdate_params.h +++ b/src/utils/knsupdate/knsupdate_params.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -20,7 +20,9 @@ #include "utils/common/netio.h" #include "utils/common/params.h" +#include "utils/common/quic.h" #include "utils/common/sign.h" +#include "utils/common/tls.h" #include "libknot/libknot.h" #include "libzscanner/scanner.h" #include "contrib/ucw/lists.h" @@ -63,6 +65,10 @@ typedef struct { style_t style; /*!< Memory context. */ knot_mm_t mm; + /*!< TLS params. */ + tls_params_t tls_params; + /*!< QUIC params. */ + quic_params_t quic_params; } knsupdate_params_t; int knsupdate_parse(knsupdate_params_t *params, int argc, char *argv[]); diff --git a/src/utils/kxdpgun/load_queries.c b/src/utils/kxdpgun/load_queries.c index 8ecac48..fe7c9ae 100644 --- a/src/utils/kxdpgun/load_queries.c +++ b/src/utils/kxdpgun/load_queries.c @@ -16,9 +16,11 @@ #include <assert.h> #include <errno.h> +#include <limits.h> #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <arpa/inet.h> #include "load_queries.h" #include "libknot/libknot.h" @@ -44,106 +46,181 @@ void free_global_payloads(void) global_payloads = NULL; } -bool load_queries(const char *filename, uint16_t edns_size, uint16_t msgid, size_t maxcount) +typedef struct { + char line[KNOT_DNAME_TXT_MAXLEN + 256]; + char dname_txt[KNOT_DNAME_TXT_MAXLEN + 1]; + uint8_t dname[KNOT_DNAME_MAXLEN]; + char type_txt[128]; + char flags_txt[128]; +} txt_bufs_t; + +typedef struct { + char line[USHRT_MAX]; +} bin_bufs_t; + +static int read_txt(struct pkt_payload **g_payloads_top_p, FILE *f, txt_bufs_t *bufs, + uint16_t edns_size, uint16_t msgid) +{ + assert(g_payloads_top_p != NULL); + struct pkt_payload *g_payloads_top = *g_payloads_top_p; + if (fgets(bufs->line, sizeof(bufs->line), f) == NULL) { + return 0; + } + bufs->flags_txt[0] = '\0'; + int ret = sscanf(bufs->line, "%s%s%s", bufs->dname_txt, bufs->type_txt, + bufs->flags_txt); + if (ret < 2) { + ERR2(ERR_PREFIX "(faulty line): '%.*s'", + (int)strcspn(bufs->line, "\n"), bufs->line); + return KNOT_EINVAL; + } + + void *pret = knot_dname_from_str(bufs->dname, bufs->dname_txt, sizeof(bufs->dname)); + if (pret == NULL) { + ERR2(ERR_PREFIX "(faulty dname): '%s'", bufs->dname_txt); + return KNOT_EINVAL; + } + + uint16_t type; + ret = knot_rrtype_from_string(bufs->type_txt, &type); + if (ret < 0) { + ERR2(ERR_PREFIX "(faulty type): '%s'", bufs->type_txt); + return KNOT_EINVAL; + } + + enum qflags flags = 0; + switch (bufs->flags_txt[0]) { + case '\0': + break; + case 'e': + case 'E': + flags |= QFLAG_EDNS; + break; + case 'd': + case 'D': + flags |= QFLAG_EDNS | QFLAG_DO; + break; + default: + ERR2(ERR_PREFIX "(faulty flag): '%s'", bufs->flags_txt); + return KNOT_EINVAL; + } + + size_t dname_len = knot_dname_size(bufs->dname); + size_t pkt_len = KNOT_WIRE_HEADER_SIZE + 2 * sizeof(uint16_t) + dname_len; + if (flags & QFLAG_EDNS) { + pkt_len += KNOT_EDNS_MIN_SIZE; + } + + struct pkt_payload *pkt = calloc(1, sizeof(*pkt) + pkt_len); + if (pkt == NULL) { + ERR2(ERR_PREFIX "(out of memory)"); + return KNOT_ENOMEM; + } + pkt->len = pkt_len; + memcpy(pkt->payload, &msgid, sizeof(msgid)); + pkt->payload[2] = 0x01; // RD bit + pkt->payload[5] = 0x01; // 1 question + pkt->payload[11] = (flags & QFLAG_EDNS) ? 0x01 : 0x00; + memcpy(pkt->payload + 12, bufs->dname, dname_len); + pkt->payload[dname_len + 12] = type >> 8; + pkt->payload[dname_len + 13] = type & 0xff; + pkt->payload[dname_len + 15] = KNOT_CLASS_IN; + if (flags & QFLAG_EDNS) { + pkt->payload[dname_len + 18] = KNOT_RRTYPE_OPT; + pkt->payload[dname_len + 19] = edns_size >> 8; + pkt->payload[dname_len + 20] = edns_size & 0xff; + pkt->payload[dname_len + 23] = (flags & QFLAG_DO) ? 0x80 : 0x00; + } + + // add pkt to list global_payloads + if (g_payloads_top == NULL) { + global_payloads = pkt; + *g_payloads_top_p = pkt; + } else { + g_payloads_top->next = pkt; + *g_payloads_top_p = pkt; + } + return pkt_len; +} + +static int read_bin(struct pkt_payload **g_payloads_top_p, FILE *f, bin_bufs_t *bufs, + uint16_t msgid) +{ + assert(g_payloads_top_p != NULL); + struct pkt_payload *g_payloads_top = *g_payloads_top_p; + uint16_t size; + if (fread(&size, sizeof(size), 1, f) < 1) { + return 0; + } + size = ntohs(size); + if (fread(bufs->line, size, 1, f) < 1) { + return KNOT_EINVAL; + } + struct pkt_payload *pkt = calloc(1, sizeof(*pkt) + size); + if (pkt == NULL) { + ERR2(ERR_PREFIX "(out of memory)"); + return KNOT_ENOMEM; + } + pkt->len = size; + memcpy(pkt->payload, &msgid, sizeof(msgid)); // Override msgID + memcpy(pkt->payload + 2, bufs->line + 2, size - 2); + + // add pkt to list global_payloads + if (g_payloads_top == NULL) { + global_payloads = pkt; + *g_payloads_top_p = pkt; + } else { + g_payloads_top->next = pkt; + *g_payloads_top_p = pkt; + } + return size; +} + +bool load_queries(const input_t *input, uint16_t edns_size, uint16_t msgid, size_t maxcount) { size_t read = 0; - FILE *f = fopen(filename, "r"); + FILE *f = fopen(input->path, (input->format == BIN) ? "rb" : "r"); if (f == NULL) { - ERR2(ERR_PREFIX "file '%s' (%s)", filename, strerror(errno)); + ERR2(ERR_PREFIX "file '%s' (%s)", input->path, strerror(errno)); return false; } - struct pkt_payload *g_payloads_top = NULL; - struct { - char line[KNOT_DNAME_TXT_MAXLEN + 256]; - char dname_txt[KNOT_DNAME_TXT_MAXLEN + 1]; - uint8_t dname[KNOT_DNAME_MAXLEN]; - char type_txt[128]; - char flags_txt[128]; - } *bufs; - bufs = malloc(sizeof(*bufs)); // avoiding too much stuff on stack + void *bufs = NULL; + switch (input->format) { + case TXT: + bufs = malloc(sizeof(txt_bufs_t)); // avoiding too much stuff on stack + break; + case BIN: + bufs = malloc(sizeof(bin_bufs_t)); + break; + default: + assert(0); + goto fail; + } if (bufs == NULL) { ERR2(ERR_PREFIX "(out of memory)"); goto fail; } + struct pkt_payload *g_payloads_top = NULL; while (read < maxcount) { - if (fgets(bufs->line, sizeof(bufs->line), f) == NULL) { + int ret = 0; + switch (input->format) { + case TXT: + ret = read_txt(&g_payloads_top, f, bufs, edns_size, msgid); break; - } - bufs->flags_txt[0] = '\0'; - int ret = sscanf(bufs->line, "%s%s%s", bufs->dname_txt, bufs->type_txt, bufs->flags_txt); - if (ret < 2) { - ERR2(ERR_PREFIX "(faulty line): '%.*s'", - (int)strcspn(bufs->line, "\n"), bufs->line); - goto fail; - } - - void *pret = knot_dname_from_str(bufs->dname, bufs->dname_txt, sizeof(bufs->dname)); - if (pret == NULL) { - ERR2(ERR_PREFIX "(faulty dname): '%s'", bufs->dname_txt); - goto fail; - } - - uint16_t type; - ret = knot_rrtype_from_string(bufs->type_txt, &type); - if (ret < 0) { - ERR2(ERR_PREFIX "(faulty type): '%s'", bufs->type_txt); - goto fail; - } - - enum qflags flags = 0; - switch (bufs->flags_txt[0]) { - case '\0': - break; - case 'e': - case 'E': - flags |= QFLAG_EDNS; - break; - case 'd': - case 'D': - flags |= QFLAG_EDNS | QFLAG_DO; + case BIN: + ret = read_bin(&g_payloads_top, f, bufs, msgid); break; default: - ERR2(ERR_PREFIX "(faulty flag): '%s'", bufs->flags_txt); - goto fail; - } - - size_t dname_len = knot_dname_size(bufs->dname); - size_t pkt_len = KNOT_WIRE_HEADER_SIZE + 2 * sizeof(uint16_t) + dname_len; - if (flags & QFLAG_EDNS) { - pkt_len += KNOT_EDNS_MIN_SIZE; + ret = -1; + break; } - - struct pkt_payload *pkt = calloc(1, sizeof(struct pkt_payload) + pkt_len); - if (pkt == NULL) { - ERR2(ERR_PREFIX "(out of memory)"); + if (ret == 0) { + break; + } else if (ret < 0) { goto fail; } - pkt->len = pkt_len; - memcpy(pkt->payload, &msgid, sizeof(msgid)); - pkt->payload[2] = 0x01; // RD bit - pkt->payload[5] = 0x01; // 1 question - pkt->payload[11] = (flags & QFLAG_EDNS) ? 0x01 : 0x00; - memcpy(pkt->payload + 12, bufs->dname, dname_len); - pkt->payload[dname_len + 12] = type >> 8; - pkt->payload[dname_len + 13] = type & 0xff; - pkt->payload[dname_len + 15] = KNOT_CLASS_IN; - if (flags & QFLAG_EDNS) { - pkt->payload[dname_len + 18] = KNOT_RRTYPE_OPT; - pkt->payload[dname_len + 19] = edns_size >> 8; - pkt->payload[dname_len + 20] = edns_size & 0xff; - pkt->payload[dname_len + 23] = (flags & QFLAG_DO) ? 0x80 : 0x00; - } - - // add pkt to list global_payloads - if (g_payloads_top == NULL) { - global_payloads = pkt; - g_payloads_top = pkt; - } else { - g_payloads_top->next = pkt; - g_payloads_top = pkt; - } read++; } diff --git a/src/utils/kxdpgun/load_queries.h b/src/utils/kxdpgun/load_queries.h index 3d7bace..09dfee9 100644 --- a/src/utils/kxdpgun/load_queries.h +++ b/src/utils/kxdpgun/load_queries.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -19,6 +19,16 @@ #include <stdbool.h> #include <stdint.h> +enum input_format { + TXT = 0, + BIN +}; + +typedef struct { + const char *path; + enum input_format format; +} input_t; + struct pkt_payload { struct pkt_payload *next; size_t len; @@ -27,6 +37,6 @@ struct pkt_payload { extern struct pkt_payload *global_payloads; -bool load_queries(const char *filename, uint16_t edns_size, uint16_t msgid, size_t maxcount); +bool load_queries(const input_t *input, uint16_t edns_size, uint16_t msgid, size_t maxcount); void free_global_payloads(void); diff --git a/src/utils/kxdpgun/main.c b/src/utils/kxdpgun/main.c index 523f64f..4e3aa31 100644 --- a/src/utils/kxdpgun/main.c +++ b/src/utils/kxdpgun/main.c @@ -14,12 +14,15 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. */ +#include <arpa/inet.h> #include <assert.h> #include <errno.h> #include <getopt.h> #include <ifaddrs.h> #include <inttypes.h> #include <net/if.h> +#include <netdb.h> +#include <netinet/in.h> #include <poll.h> #include <pthread.h> #include <signal.h> @@ -28,16 +31,11 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <time.h> -#include <unistd.h> -#include <netdb.h> - -#include <arpa/inet.h> -#include <netinet/in.h> -#include <net/if.h> #include <sys/ioctl.h> -#include <sys/socket.h> #include <sys/resource.h> +#include <sys/socket.h> +#include <time.h> +#include <unistd.h> #include "libknot/libknot.h" #include "libknot/xdp.h" @@ -46,101 +44,28 @@ #include <gnutls/gnutls.h> #include "libknot/quic/quic.h" #endif // ENABLE_QUIC -#include "contrib/macros.h" -#include "contrib/mempattern.h" -#include "contrib/openbsd/strlcat.h" +#include "contrib/atomic.h" #include "contrib/openbsd/strlcpy.h" #include "contrib/os.h" #include "contrib/sockaddr.h" #include "contrib/toeplitz.h" -#include "contrib/ucw/mempool.h" #include "utils/common/msg.h" #include "utils/common/params.h" #include "utils/kxdpgun/ip_route.h" #include "utils/kxdpgun/load_queries.h" - -#define PROGRAM_NAME "kxdpgun" -#define SPACE " " - -enum { - KXDPGUN_WAIT, - KXDPGUN_START, - KXDPGUN_STOP, -}; +#include "utils/kxdpgun/main.h" +#include "utils/kxdpgun/stats.h" volatile int xdp_trigger = KXDPGUN_WAIT; -volatile unsigned stats_trigger = 0; +volatile knot_atomic_uint64_t stats_trigger = 0; +volatile knot_atomic_bool stats_switch = STATS_SUM; unsigned global_cpu_aff_start = 0; unsigned global_cpu_aff_step = 1; -#define REMOTE_PORT_DEFAULT 53 -#define REMOTE_PORT_DOQ_DEFAULT 853 -#define LOCAL_PORT_MIN 2000 -#define LOCAL_PORT_MAX 65535 -#define QUIC_THREAD_PORTS 100 - -#define RCODE_MAX (0x0F + 1) - -typedef struct { - size_t collected; - uint64_t duration; - uint64_t qry_sent; - uint64_t synack_recv; - uint64_t ans_recv; - uint64_t finack_recv; - uint64_t rst_recv; - uint64_t size_recv; - uint64_t wire_recv; - uint64_t rcodes_recv[RCODE_MAX]; - pthread_mutex_t mutex; -} kxdpgun_stats_t; - static kxdpgun_stats_t global_stats = { 0 }; -typedef enum { - KXDPGUN_IGNORE_NONE = 0, - KXDPGUN_IGNORE_QUERY = (1 << 0), - KXDPGUN_IGNORE_LASTBYTE = (1 << 1), - KXDPGUN_IGNORE_CLOSE = (1 << 2), - KXDPGUN_REUSE_CONN = (1 << 3), -} xdp_gun_ignore_t; - -typedef struct { - union { - struct sockaddr_in local_ip4; - struct sockaddr_in6 local_ip; - struct sockaddr_storage local_ip_ss; - }; - union { - struct sockaddr_in target_ip4; - struct sockaddr_in6 target_ip; - struct sockaddr_storage target_ip_ss; - }; - char dev[IFNAMSIZ]; - uint64_t qps, duration; - unsigned at_once; - uint16_t msgid; - uint16_t edns_size; - uint16_t vlan_tci; - uint8_t local_mac[6], target_mac[6]; - uint8_t local_ip_range; - bool ipv6; - bool tcp; - bool quic; - bool quic_full_handshake; - const char *qlog_dir; - const char *sending_mode; - xdp_gun_ignore_t ignore1; - knot_tcp_ignore_t ignore2; - uint16_t target_port; - knot_xdp_filter_flag_t flags; - unsigned n_threads, thread_id; - knot_eth_rss_conf_t *rss_conf; - knot_xdp_config_t xdp_config; -} xdp_gun_ctx_t; - const static xdp_gun_ctx_t ctx_defaults = { .dev[0] = '\0', .edns_size = 1232, @@ -150,7 +75,9 @@ const static xdp_gun_ctx_t ctx_defaults = { .sending_mode = "", .target_port = 0, .flags = KNOT_XDP_FILTER_UDP | KNOT_XDP_FILTER_PASS, - .xdp_config = { .extra_frames = true }, + .xdp_config = { .ring_size = 2048 }, + .jw = NULL, + .stats_period = 0, }; static void sigterm_handler(int signo) @@ -163,103 +90,8 @@ static void sigusr_handler(int signo) { assert(signo == SIGUSR1); if (global_stats.collected == 0) { - stats_trigger++; - } -} - -static void clear_stats(kxdpgun_stats_t *st) -{ - pthread_mutex_lock(&st->mutex); - st->duration = 0; - st->qry_sent = 0; - st->synack_recv = 0; - st->ans_recv = 0; - st->finack_recv = 0; - st->rst_recv = 0; - st->size_recv = 0; - st->wire_recv = 0; - st->collected = 0; - memset(st->rcodes_recv, 0, sizeof(st->rcodes_recv)); - pthread_mutex_unlock(&st->mutex); -} - -static size_t collect_stats(kxdpgun_stats_t *into, const kxdpgun_stats_t *what) -{ - pthread_mutex_lock(&into->mutex); - into->duration = MAX(into->duration, what->duration); - into->qry_sent += what->qry_sent; - into->synack_recv += what->synack_recv; - into->ans_recv += what->ans_recv; - into->finack_recv += what->finack_recv; - into->rst_recv += what->rst_recv; - into->size_recv += what->size_recv; - into->wire_recv += what->wire_recv; - for (int i = 0; i < RCODE_MAX; i++) { - into->rcodes_recv[i] += what->rcodes_recv[i]; + ATOMIC_ADD(stats_trigger, 1); } - size_t res = ++into->collected; - pthread_mutex_unlock(&into->mutex); - return res; -} - -static void print_stats(kxdpgun_stats_t *st, bool tcp, bool quic, bool recv, uint64_t qps) -{ - pthread_mutex_lock(&st->mutex); - -#define ps(counter) ((typeof(counter))((counter) * 1000 / ((float)st->duration / 1000))) -#define pct(counter) ((counter) * 100.0 / st->qry_sent) - - const char *name = tcp ? "SYNs: " : quic ? "initials:" : "queries: "; - printf("total %s %"PRIu64" (%"PRIu64" pps) (%f%%)\n", name, st->qry_sent, - ps(st->qry_sent), 100.0 * st->qry_sent / (st->duration / 1000000.0 * qps)); - if (st->qry_sent > 0 && recv) { - if (tcp || quic) { - name = tcp ? "established:" : "handshakes: "; - printf("total %s %"PRIu64" (%"PRIu64" pps) (%f%%)\n", name, - st->synack_recv, ps(st->synack_recv), pct(st->synack_recv)); - } - printf("total replies: %"PRIu64" (%"PRIu64" pps) (%f%%)\n", - st->ans_recv, ps(st->ans_recv), pct(st->ans_recv)); - if (tcp) { - printf("total closed: %"PRIu64" (%"PRIu64" pps) (%f%%)\n", - st->finack_recv, ps(st->finack_recv), pct(st->finack_recv)); - } - if (st->rst_recv > 0) { - printf("total reset: %"PRIu64" (%"PRIu64" pps) (%f%%)\n", - st->rst_recv, ps(st->rst_recv), pct(st->rst_recv)); - } - printf("average DNS reply size: %"PRIu64" B\n", - st->ans_recv > 0 ? st->size_recv / st->ans_recv : 0); - printf("average Ethernet reply rate: %"PRIu64" bps (%.2f Mbps)\n", - ps(st->wire_recv * 8), ps((float)st->wire_recv * 8 / (1000 * 1000))); - - for (int i = 0; i < RCODE_MAX; i++) { - if (st->rcodes_recv[i] > 0) { - const knot_lookup_t *rcode = knot_lookup_by_id(knot_rcode_names, i); - const char *rcname = rcode == NULL ? "unknown" : rcode->name; - int space = MAX(9 - strlen(rcname), 0); - printf("responded %s: %.*s%"PRIu64"\n", - rcname, space, " ", st->rcodes_recv[i]); - } - } - } - printf("duration: %"PRIu64" s\n", (st->duration / (1000 * 1000))); - - pthread_mutex_unlock(&st->mutex); -} - -inline static void timer_start(struct timespec *timesp) -{ - clock_gettime(CLOCK_MONOTONIC, timesp); -} - -inline static uint64_t timer_end(struct timespec *timesp) -{ - struct timespec end; - clock_gettime(CLOCK_MONOTONIC, &end); - uint64_t res = (end.tv_sec - timesp->tv_sec) * (uint64_t)1000000; - res += ((int64_t)end.tv_nsec - timesp->tv_nsec) / 1000; - return res; } static unsigned addr_bits(bool ipv6) @@ -267,7 +99,8 @@ static unsigned addr_bits(bool ipv6) return ipv6 ? 128 : 32; } -static void shuffle_sockaddr4(struct sockaddr_in *dst, struct sockaddr_in *src, uint64_t increment) +static void shuffle_sockaddr4(struct sockaddr_in *dst, struct sockaddr_in *src, + uint64_t increment) { memcpy(&dst->sin_addr, &src->sin_addr, sizeof(dst->sin_addr)); if (increment > 0) { @@ -275,7 +108,8 @@ static void shuffle_sockaddr4(struct sockaddr_in *dst, struct sockaddr_in *src, } } -static void shuffle_sockaddr6(struct sockaddr_in6 *dst, struct sockaddr_in6 *src, uint64_t increment) +static void shuffle_sockaddr6(struct sockaddr_in6 *dst, struct sockaddr_in6 *src, + uint64_t increment) { memcpy(&dst->sin6_addr, &src->sin6_addr, sizeof(dst->sin6_addr)); if (increment > 0) { @@ -293,7 +127,8 @@ static void shuffle_sockaddr(struct sockaddr_in6 *dst, struct sockaddr_in6 *src, if (src->sin6_family == AF_INET6) { shuffle_sockaddr6(dst, src, increment); } else { - shuffle_sockaddr4((struct sockaddr_in *)dst, (struct sockaddr_in *)src, increment); + shuffle_sockaddr4((struct sockaddr_in *)dst, (struct sockaddr_in *)src, + increment); } } @@ -311,7 +146,8 @@ static void next_payload(struct pkt_payload **payload, int increment) } } -static void put_dns_payload(struct iovec *put_into, bool zero_copy, xdp_gun_ctx_t *ctx, struct pkt_payload **payl) +static void put_dns_payload(struct iovec *put_into, bool zero_copy, xdp_gun_ctx_t *ctx, + struct pkt_payload **payl) { if (zero_copy) { put_into->iov_base = (*payl)->payload; @@ -472,19 +308,41 @@ static void quic_free_cb(knot_quic_reply_t *rpl) } #endif // ENABLE_QUIC +static uint64_t timestamp_ns(void) +{ + struct timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + return ((uint64_t)ts.tv_sec * 1000000000) + ts.tv_nsec; +} + +static void timer_start(struct timespec *out) +{ + clock_gettime(CLOCK_MONOTONIC, out); +} + +static uint64_t timer_end_ns(const struct timespec *start) +{ + struct timespec end; + clock_gettime(CLOCK_MONOTONIC, &end); + uint64_t res = (end.tv_sec - start->tv_sec) * (uint64_t)1000000000; + res += end.tv_nsec - start->tv_nsec; + return res; +} + void *xdp_gun_thread(void *_ctx) { xdp_gun_ctx_t *ctx = _ctx; struct knot_xdp_socket *xsk = NULL; - struct timespec timer; knot_xdp_msg_t pkts[ctx->at_once]; - uint64_t errors = 0, lost = 0, duration = 0; - kxdpgun_stats_t local_stats = { 0 }; + uint64_t duration_us = 0; + struct timespec timer; + kxdpgun_stats_t local_stats = { 0 }; // cumulative stats of past periods excluding the current + kxdpgun_stats_t periodic_stats = { 0 }; // stats for the current period (see -S option) unsigned stats_triggered = 0; knot_tcp_table_t *tcp_table = NULL; #ifdef ENABLE_QUIC knot_quic_table_t *quic_table = NULL; - struct knot_quic_creds *quic_creds = NULL; + struct knot_creds *quic_creds = NULL; list_t quic_sessions; init_list(&quic_sessions); #endif // ENABLE_QUIC @@ -501,12 +359,13 @@ void *xdp_gun_thread(void *_ctx) } if (ctx->quic) { #ifdef ENABLE_QUIC - quic_creds = knot_quic_init_creds_peer(NULL, NULL, 0); + quic_creds = knot_creds_init_peer(NULL, NULL, 0); if (quic_creds == NULL) { ERR2("failed to initialize QUIC context"); goto cleanup; } - quic_table = knot_quic_table_new(ctx->qps * 100, SIZE_MAX, SIZE_MAX, 1232, quic_creds); + quic_table = knot_quic_table_new(ctx->qps * 100, SIZE_MAX, SIZE_MAX, + 1232, quic_creds); if (quic_table == NULL) { ERR2("failed to allocate QUIC connection table"); goto cleanup; @@ -517,12 +376,12 @@ void *xdp_gun_thread(void *_ctx) #endif // ENABLE_QUIC } - knot_xdp_load_bpf_t mode = (ctx->thread_id == 0 ? - KNOT_XDP_LOAD_BPF_ALWAYS : KNOT_XDP_LOAD_BPF_NEVER); + knot_xdp_load_bpf_t mode = + (ctx->thread_id == 0 ? KNOT_XDP_LOAD_BPF_ALWAYS : KNOT_XDP_LOAD_BPF_NEVER); /* * This mutex prevents libbpf from logging: * 'libbpf: can't get link by id (5535): Resource temporarily unavailable' - */ + */ pthread_mutex_lock(&global_stats.mutex); int ret = knot_xdp_init(&xsk, ctx->dev, ctx->thread_id, ctx->flags, LOCAL_PORT_MIN, LOCAL_PORT_MIN, mode, &ctx->xdp_config); @@ -534,13 +393,7 @@ void *xdp_gun_thread(void *_ctx) } if (ctx->thread_id == 0) { - INFO2("using interface %s, XDP threads %u, IPv%c/%s%s%s, %s mode", - ctx->dev, ctx->n_threads, (ctx->ipv6 ? '6' : '4'), - (ctx->tcp ? "TCP" : ctx->quic ? "QUIC" : "UDP"), - (ctx->sending_mode[0] != '\0' ? " mode " : ""), - (ctx->sending_mode[0] != '\0' ? ctx->sending_mode : ""), - (knot_eth_xdp_mode(if_nametoindex(ctx->dev)) == KNOT_XDP_MODE_FULL ? - "native" : "emulated")); + STATS_HDR(ctx); } struct pollfd pfd = { knot_xdp_socket_fd(xsk), POLLIN, 0 }; @@ -576,7 +429,7 @@ void *xdp_gun_thread(void *_ctx) ctx->target_ip.sin6_port = htobe16(ctx->target_port); knot_sweep_stats_t sweep_stats = { 0 }; - uint16_t local_ports[QUIC_THREAD_PORTS]; + uint16_t local_ports[QUIC_THREAD_PORTS] = { 0 }; uint16_t port = LOCAL_PORT_MIN; for (int i = 0; ctx->quic && i < QUIC_THREAD_PORTS; ++i) { local_ports[i] = adjust_port(ctx, port); @@ -586,24 +439,25 @@ void *xdp_gun_thread(void *_ctx) size_t local_ports_it = 0; #endif // ENABLE_QUIC + local_stats.since = periodic_stats.since = timestamp_ns(); timer_start(&timer); + ctx->stats_start_us = local_stats.since / 1000; - while (duration < ctx->duration + extra_wait) { - + while (duration_us < ctx->duration + extra_wait) { // sending part - if (duration < ctx->duration) { + if (duration_us < ctx->duration) { while (1) { knot_xdp_send_prepare(xsk); unsigned alloced = alloc_pkts(pkts, xsk, ctx, tick); if (alloced < ctx->at_once) { - lost += ctx->at_once - alloced; + periodic_stats.lost += ctx->at_once - alloced; if (alloced == 0) { break; } } if (ctx->tcp) { - for (int i = 0; i < alloced; i++) { + for (uint32_t i = 0; i < alloced; i++) { pkts[i].payload.iov_len = 0; if (!EMPTY_LIST(reuse_conns)) { @@ -621,7 +475,7 @@ void *xdp_gun_thread(void *_ctx) } if (ret == KNOT_EOK) { pkts[i].flags &= ~KNOT_XDP_MSG_SYN; // skip sending respective packet - local_stats.qry_sent++; + periodic_stats.qry_sent++; } free(rl); } @@ -670,14 +524,14 @@ void *xdp_gun_thread(void *_ctx) (ctx->ignore1 & KXDPGUN_IGNORE_LASTBYTE) ? KNOT_QUIC_SEND_IGNORE_LASTBYTE : 0); } if (ret == KNOT_EOK) { - local_stats.qry_sent++; + periodic_stats.qry_sent++; } } (void)knot_xdp_send_finish(xsk); #endif // ENABLE_QUIC break; } else { - for (int i = 0; i < alloced; i++) { + for (uint32_t i = 0; i < alloced; i++) { put_dns_payload(&pkts[i].payload, false, ctx, &payload_ptr); } @@ -685,9 +539,9 @@ void *xdp_gun_thread(void *_ctx) uint32_t really_sent = 0; if (knot_xdp_send(xsk, pkts, alloced, &really_sent) != KNOT_EOK) { - lost += alloced; + periodic_stats.lost += alloced; } - local_stats.qry_sent += really_sent; + periodic_stats.qry_sent += really_sent; (void)knot_xdp_send_finish(xsk); break; @@ -699,7 +553,7 @@ void *xdp_gun_thread(void *_ctx) while (1) { ret = poll(&pfd, 1, 0); if (ret < 0) { - errors++; + periodic_stats.errors++; break; } if (!pfd.revents) { @@ -714,18 +568,19 @@ void *xdp_gun_thread(void *_ctx) } if (ctx->tcp) { knot_tcp_relay_t relays[recvd]; - ret = knot_tcp_recv(relays, pkts, recvd, tcp_table, NULL, ctx->ignore2); - if (ret != KNOT_EOK) { - errors++; - break; - } for (size_t i = 0; i < recvd; i++) { knot_tcp_relay_t *rl = &relays[i]; + ret = knot_tcp_recv(rl, &pkts[i], tcp_table, NULL, ctx->ignore2); + if (ret != KNOT_EOK) { + periodic_stats.errors++; + continue; + } + struct iovec payl; switch (rl->action) { case XDP_TCP_ESTABLISH: - local_stats.synack_recv++; + periodic_stats.synack_recv++; if (ctx->ignore1 & KXDPGUN_IGNORE_QUERY) { break; } @@ -734,20 +589,20 @@ void *xdp_gun_thread(void *_ctx) (ctx->ignore1 & KXDPGUN_IGNORE_LASTBYTE), payl.iov_base, payl.iov_len); if (ret != KNOT_EOK) { - errors++; + periodic_stats.errors++; } break; case XDP_TCP_CLOSE: - local_stats.finack_recv++; + periodic_stats.finack_recv++; break; case XDP_TCP_RESET: - local_stats.rst_recv++; + periodic_stats.rst_recv++; break; default: break; } for (size_t j = 0; rl->inbf != NULL && j < rl->inbf->n_inbufs; j++) { - if (check_dns_payload(&rl->inbf->inbufs[j], ctx, &local_stats)) { + if (check_dns_payload(&rl->inbf->inbufs[j], ctx, &periodic_stats)) { if (!(ctx->ignore1 & KXDPGUN_IGNORE_CLOSE)) { rl->answer = XDP_TCP_CLOSE; } else if ((ctx->ignore1 & KXDPGUN_REUSE_CONN)) { @@ -763,7 +618,7 @@ void *xdp_gun_thread(void *_ctx) ret = knot_tcp_send(xsk, relays, recvd, ctx->at_once); if (ret != KNOT_EOK) { - errors++; + periodic_stats.errors++; } (void)knot_xdp_send_finish(xsk); @@ -781,11 +636,11 @@ void *xdp_gun_thread(void *_ctx) ret = knot_quic_handle(quic_table, &quic_reply, 5000000000L, &conn); if (ret == KNOT_ECONN) { - local_stats.rst_recv++; + periodic_stats.rst_recv++; knot_quic_cleanup(&conn, 1); continue; } else if (ret != 0) { - errors++; + periodic_stats.errors++; knot_quic_cleanup(&conn, 1); break; } @@ -805,7 +660,7 @@ void *xdp_gun_thread(void *_ctx) if ((conn->flags & KNOT_QUIC_CONN_HANDSHAKE_DONE) && conn->streams_count == -1) { conn->streams_count = 1; - local_stats.synack_recv++; + periodic_stats.synack_recv++; if ((ctx->ignore1 & KXDPGUN_IGNORE_QUERY)) { knot_quic_table_rem(conn, quic_table); knot_quic_cleanup(&conn, 1); @@ -822,14 +677,14 @@ void *xdp_gun_thread(void *_ctx) if ((ctx->ignore2 & XDP_TCP_IGNORE_ESTABLISH)) { knot_quic_table_rem(conn, quic_table); knot_quic_cleanup(&conn, 1); - local_stats.synack_recv++; + periodic_stats.synack_recv++; continue; } int64_t s0id; knot_quic_stream_t *stream0 = knot_quic_stream_get_process(conn, &s0id); if (stream0 != NULL && stream0->inbufs != NULL && stream0->inbufs->n_inbufs > 0) { - check_dns_payload(&stream0->inbufs->inbufs[0], ctx, &local_stats); + check_dns_payload(&stream0->inbufs->inbufs[0], ctx, &periodic_stats); stream0->inbufs->n_inbufs = 0; // signal that data have been read out if ((ctx->ignore2 & XDP_TCP_IGNORE_DATA_ACK)) { @@ -837,7 +692,9 @@ void *xdp_gun_thread(void *_ctx) knot_quic_cleanup(&conn, 1); continue; } else if ((ctx->ignore1 & KXDPGUN_REUSE_CONN)) { - if (conn->streams_count > 1) { // keep the number of outstanding streams below MAX_STREAMS_PER_CONN, while preserving at least one at all times + /* keep the number of outstanding streams below MAX_STREAMS_PER_CONN, + * while preserving at least one at all times */ + if (conn->streams_count > 1) { knot_quic_conn_stream_free(conn, conn->streams_first * 4); } ptrlist_add(&reuse_conns, conn, NULL); @@ -846,30 +703,31 @@ void *xdp_gun_thread(void *_ctx) ret = knot_quic_send(quic_table, conn, &quic_reply, 4, (ctx->ignore1 & KXDPGUN_IGNORE_LASTBYTE) ? KNOT_QUIC_SEND_IGNORE_LASTBYTE : 0); if (ret != KNOT_EOK) { - errors++; + periodic_stats.errors++; } - if (!(ctx->ignore1 & KXDPGUN_IGNORE_CLOSE) && (conn->flags & KNOT_QUIC_CONN_SESSION_TAKEN) && - stream0 != NULL && stream0->inbufs != NULL && stream0->inbufs->n_inbufs == 0) { + if (!(ctx->ignore1 & KXDPGUN_IGNORE_CLOSE) + && (conn->flags & KNOT_QUIC_CONN_SESSION_TAKEN) + && stream0 != NULL && stream0->inbufs != NULL + && stream0->inbufs->n_inbufs == 0) { assert(!(ctx->ignore2 & XDP_TCP_IGNORE_DATA_ACK)); quic_reply.handle_ret = KNOT_QUIC_HANDLE_RET_CLOSE; ret = knot_quic_send(quic_table, conn, &quic_reply, 1, 0); knot_quic_table_rem(conn, quic_table); knot_quic_cleanup(&conn, 1); if (ret != KNOT_EOK) { - errors++; + periodic_stats.errors++; } } } (void)knot_xdp_send_finish(xsk); #endif // ENABLE_QUIC } else { - for (int i = 0; i < recvd; i++) { - (void)check_dns_payload(&pkts[i].payload, ctx, - &local_stats); + for (uint32_t i = 0; i < recvd; i++) { + check_dns_payload(&pkts[i].payload, ctx, &periodic_stats); } } - local_stats.wire_recv += wire; + periodic_stats.wire_recv += wire; knot_xdp_recv_finish(xsk, pkts, recvd); pfd.revents = 0; } @@ -882,47 +740,59 @@ void *xdp_gun_thread(void *_ctx) #endif // ENABLE_QUIC // speed and signal part - uint64_t dura_exp = (local_stats.qry_sent * 1000000) / ctx->qps; - duration = timer_end(&timer); - if (xdp_trigger == KXDPGUN_STOP && ctx->duration > duration) { - ctx->duration = duration; + uint64_t duration_ns = timer_end_ns(&timer); + duration_us = duration_ns / 1000; + uint64_t dura_exp = ((local_stats.qry_sent + periodic_stats.qry_sent) * 1000000) / ctx->qps; + if (ctx->thread_id == 0 && ctx->stats_period != 0 && global_stats.collected == 0 + && (duration_ns - (periodic_stats.since - local_stats.since)) >= ctx->stats_period) { + ATOMIC_SET(stats_switch, STATS_PERIODIC); + ATOMIC_ADD(stats_trigger, 1); } - if (stats_trigger > stats_triggered) { - assert(stats_trigger == stats_triggered + 1); - stats_triggered++; - local_stats.duration = duration; - size_t collected = collect_stats(&global_stats, &local_stats); + if (xdp_trigger == KXDPGUN_STOP && ctx->duration > duration_us) { + ctx->duration = duration_us; + } + uint64_t tmp_stats_trigger = ATOMIC_GET(stats_trigger); + if (duration_us < ctx->duration && tmp_stats_trigger > stats_triggered) { + bool tmp_stats_switch = ATOMIC_GET(stats_switch); + stats_triggered = tmp_stats_trigger; + + local_stats.until = periodic_stats.until = local_stats.since + duration_ns; + kxdpgun_stats_t cumulative_stats = periodic_stats; + if (tmp_stats_switch == STATS_PERIODIC) { + collect_periodic_stats(&local_stats, &periodic_stats); + clear_stats(&periodic_stats); + periodic_stats.since = local_stats.since + duration_ns; + } else { + collect_periodic_stats(&cumulative_stats, &local_stats); + cumulative_stats.since = local_stats.since; + } + + size_t collected = collect_stats(&global_stats, &cumulative_stats); + assert(collected <= ctx->n_threads); if (collected == ctx->n_threads) { - print_stats(&global_stats, ctx->tcp, ctx->quic, - !(ctx->flags & KNOT_XDP_FILTER_DROP), - ctx->qps * ctx->n_threads); + STATS_FMT(ctx, &global_stats, tmp_stats_switch); + if (!JSON_MODE(*ctx)) { + puts(STATS_SECTION_SEP); + } clear_stats(&global_stats); + ATOMIC_SET(stats_switch, STATS_SUM); } } - if (dura_exp > duration) { - usleep(dura_exp - duration); + if (dura_exp > duration_us) { + usleep(dura_exp - duration_us); } - if (duration > ctx->duration) { + if (duration_us > ctx->duration) { usleep(1000); } tick++; } + periodic_stats.until = local_stats.since + timer_end_ns(&timer) - extra_wait * 1000; + collect_periodic_stats(&local_stats, &periodic_stats); + + STATS_THRD(ctx, &local_stats); - char recv_str[40] = "", lost_str[40] = "", err_str[40] = ""; - if (!(ctx->flags & KNOT_XDP_FILTER_DROP)) { - (void)snprintf(recv_str, sizeof(recv_str), ", received %"PRIu64, local_stats.ans_recv); - } - if (lost > 0) { - (void)snprintf(lost_str, sizeof(lost_str), ", lost %"PRIu64, lost); - } - if (errors > 0) { - (void)snprintf(err_str, sizeof(err_str), ", errors %"PRIu64, errors); - } - INFO2("thread#%02u: sent %"PRIu64"%s%s%s", - ctx->thread_id, local_stats.qry_sent, recv_str, lost_str, err_str); - local_stats.duration = ctx->duration; collect_stats(&global_stats, &local_stats); cleanup: @@ -943,7 +813,7 @@ cleanup: WALK_LIST_DELSAFE(n, nxt, quic_sessions) { knot_quic_session_load(NULL, n); } - knot_quic_free_creds(quic_creds); + knot_creds_free(quic_creds); #endif // ENABLE_QUIC return NULL; @@ -1118,30 +988,33 @@ static void print_help(void) printf("Usage: %s [options] -i <queries_file> <dest_ip>\n" "\n" "Options:\n" - " -t, --duration <sec> "SPACE"Duration of traffic generation.\n" - " "SPACE" (default is %"PRIu64" seconds)\n" - " -T, --tcp[=debug_mode] "SPACE"Send queries over TCP.\n" - " -U, --quic[=debug_mode] "SPACE"Send queries over QUIC.\n" - " -Q, --qps <qps> "SPACE"Number of queries-per-second (approximately) to be sent.\n" - " "SPACE" (default is %"PRIu64" qps)\n" - " -b, --batch <size> "SPACE"Send queries in a batch of defined size.\n" - " "SPACE" (default is %d for UDP, %d for TCP)\n" - " -r, --drop "SPACE"Drop incoming responses (disables response statistics).\n" - " -p, --port <port> "SPACE"Remote destination port.\n" - " "SPACE" (default is %d for UDP/TCP, %u for QUIC)\n" - " -F, --affinity <spec> "SPACE"CPU affinity in the format [<cpu_start>][s<cpu_step>].\n" - " "SPACE" (default is %s)\n" - " -i, --infile <file> "SPACE"Path to a file with query templates.\n" - " -I, --interface <ifname> "SPACE"Override auto-detected interface for outgoing communication.\n" - " -l, --local <ip[/prefix]>"SPACE"Override auto-detected source IP address or subnet.\n" - " -L, --local-mac <MAC> "SPACE"Override auto-detected local MAC address.\n" - " -R, --remote-mac <MAC> "SPACE"Override auto-detected remote MAC address.\n" - " -v, --vlan <id> "SPACE"Add VLAN 802.1Q header with the given id.\n" - " -e, --edns-size <size> "SPACE"EDNS UDP payload size, range 512-4096 (default 1232)\n" - " -m, --mode <mode> "SPACE"Set XDP mode (auto, copy, generic).\n" - " -G, --qlog <path> "SPACE"Output directory for qlog (useful for QUIC only).\n" - " -h, --help "SPACE"Print the program help.\n" - " -V, --version "SPACE"Print the program version.\n" + " -t, --duration <sec> "SPACE"Duration of traffic generation.\n" + " "SPACE" (default is %"PRIu64" seconds)\n" + " -T, --tcp[=debug_mode] "SPACE"Send queries over TCP.\n" + " -U, --quic[=debug_mode] "SPACE"Send queries over QUIC.\n" + " -Q, --qps <qps> "SPACE"Number of queries-per-second (approximately) to be sent.\n" + " "SPACE" (default is %"PRIu64" qps)\n" + " -b, --batch <size> "SPACE"Send queries in a batch of defined size.\n" + " "SPACE" (default is %d for UDP, %d for TCP)\n" + " -r, --drop "SPACE"Drop incoming responses (disables response statistics).\n" + " -p, --port <port> "SPACE"Remote destination port.\n" + " "SPACE" (default is %d for UDP/TCP, %u for QUIC)\n" + " -F, --affinity <spec> "SPACE"CPU affinity in the format [<cpu_start>][s<cpu_step>].\n" + " "SPACE" (default is %s)\n" + " -I, --interface <ifname> "SPACE"Override auto-detected interface for outgoing communication.\n" + " -i, --infile <file> "SPACE"Path to a file with query templates.\n" + " -B, --binary "SPACE"Specify that input file is in binary format (<length:2><wire:length>).\n" + " -l, --local <ip[/prefix]> "SPACE"Override auto-detected source IP address or subnet.\n" + " -L, --local-mac <MAC> "SPACE"Override auto-detected local MAC address.\n" + " -R, --remote-mac <MAC> "SPACE"Override auto-detected remote MAC address.\n" + " -v, --vlan <id> "SPACE"Add VLAN 802.1Q header with the given id.\n" + " -e, --edns-size <size> "SPACE"EDNS UDP payload size, range 512-4096 (default 1232)\n" + " -m, --mode <mode> "SPACE"Set XDP mode (auto, copy, generic).\n" + " -G, --qlog <path> "SPACE"Output directory for qlog (useful for QUIC only).\n" + " -j, --json "SPACE"Output statistics in json.\n" + " -S, --stats-period <period>"SPACE"Enable periodic statistics printout in milliseconds.\n" + " -h, --help "SPACE"Print the program help.\n" + " -V, --version "SPACE"Print the program version.\n" "\n" "Parameters:\n" " <dest_ip> "SPACE"IPv4 or IPv6 address of the remote destination.\n", @@ -1240,40 +1113,45 @@ static int set_mode(const char *arg, knot_xdp_config_t *config) static bool get_opts(int argc, char *argv[], xdp_gun_ctx_t *ctx) { + const char *opts_str = "hV::t:Q:b:rp:T::U::F:I:i:Bl:L:R:v:e:m:G:jS:"; struct option opts[] = { - { "help", no_argument, NULL, 'h' }, - { "version", no_argument, NULL, 'V' }, - { "duration", required_argument, NULL, 't' }, - { "qps", required_argument, NULL, 'Q' }, - { "batch", required_argument, NULL, 'b' }, - { "drop", no_argument, NULL, 'r' }, - { "port", required_argument, NULL, 'p' }, - { "tcp", optional_argument, NULL, 'T' }, - { "quic", optional_argument, NULL, 'U' }, - { "affinity", required_argument, NULL, 'F' }, - { "interface", required_argument, NULL, 'I' }, - { "local", required_argument, NULL, 'l' }, - { "infile", required_argument, NULL, 'i' }, - { "local-mac", required_argument, NULL, 'L' }, - { "remote-mac", required_argument, NULL, 'R' }, - { "vlan", required_argument, NULL, 'v' }, - { "edns-size", required_argument, NULL, 'e' }, - { "mode", required_argument, NULL, 'm' }, - { "qlog", required_argument, NULL, 'G' }, - { NULL } + { "help", no_argument, NULL, 'h' }, + { "version", optional_argument, NULL, 'V' }, + { "duration", required_argument, NULL, 't' }, + { "qps", required_argument, NULL, 'Q' }, + { "batch", required_argument, NULL, 'b' }, + { "drop", no_argument, NULL, 'r' }, + { "port", required_argument, NULL, 'p' }, + { "tcp", optional_argument, NULL, 'T' }, + { "quic", optional_argument, NULL, 'U' }, + { "affinity", required_argument, NULL, 'F' }, + { "interface", required_argument, NULL, 'I' }, + { "infile", required_argument, NULL, 'i' }, + { "binary", no_argument, NULL, 'B' }, + { "local", required_argument, NULL, 'l' }, + { "local-mac", required_argument, NULL, 'L' }, + { "remote-mac", required_argument, NULL, 'R' }, + { "vlan", required_argument, NULL, 'v' }, + { "edns-size", required_argument, NULL, 'e' }, + { "mode", required_argument, NULL, 'm' }, + { "qlog", required_argument, NULL, 'G' }, + { "json", no_argument, NULL, 'j' }, + { "stats-period", required_argument, NULL, 'S' }, + { 0 } }; int opt = 0, arg; bool default_at_once = true; double argf; - char *argcp, *local_ip = NULL, *filename = NULL; - while ((opt = getopt_long(argc, argv, "hVt:Q:b:rp:T::U::F:I:l:i:L:R:v:e:m:G:", opts, NULL)) != -1) { + char *argcp, *local_ip = NULL; + input_t input = { .format = TXT }; + while ((opt = getopt_long(argc, argv, opts_str, opts, NULL)) != -1) { switch (opt) { case 'h': print_help(); exit(EXIT_SUCCESS); case 'V': - print_version(PROGRAM_NAME); + print_version(PROGRAM_NAME, optarg != NULL); exit(EXIT_SUCCESS); case 't': assert(optarg); @@ -1366,12 +1244,15 @@ static bool get_opts(int argc, char *argv[], xdp_gun_ctx_t *ctx) case 'I': strlcpy(ctx->dev, optarg, IFNAMSIZ); break; + case 'i': + input.path = optarg; + break; + case 'B': + input.format = BIN; + break; case 'l': local_ip = optarg; break; - case 'i': - filename = optarg; - break; case 'L': if (mac_sscan(optarg, ctx->local_mac) != KNOT_EOK) { ERR2("invalid local MAC address '%s'", optarg); @@ -1415,17 +1296,33 @@ static bool get_opts(int argc, char *argv[], xdp_gun_ctx_t *ctx) case 'G': ctx->qlog_dir = optarg; break; + case 'S': + assert(optarg); + arg = atoi(optarg); + if (arg > 0) { + ctx->stats_period = arg * 1000000; // convert to ns + } else { + ERR2("period must be a positive integer\n"); + return false; + } + break; + case 'j': + if ((ctx->jw = jsonw_new(stdout, JSON_INDENT)) == NULL) { + ERR2("failed to use JSON"); + return false; + } + break; default: print_help(); return false; } } - if (filename == NULL) { + if (input.path == NULL) { print_help(); return false; } size_t qcount = ctx->duration / 1000000 * ctx->qps; - if (!load_queries(filename, ctx->edns_size, ctx->msgid, qcount)) { + if (!load_queries(&input, ctx->edns_size, ctx->msgid, qcount)) { return false; } if (global_payloads == NULL || argc - optind != 1) { @@ -1452,25 +1349,29 @@ static bool get_opts(int argc, char *argv[], xdp_gun_ctx_t *ctx) int main(int argc, char *argv[]) { + int ecode = EXIT_FAILURE; + xdp_gun_ctx_t ctx = ctx_defaults, *thread_ctxs = NULL; ctx.msgid = time(NULL) % UINT16_MAX; + ctx.runid = timestamp_ns() / 1000; + ctx.argv = argv; pthread_t *threads = NULL; if (!get_opts(argc, argv, &ctx)) { - free_global_payloads(); - return EXIT_FAILURE; + goto err; + } + + if (JSON_MODE(ctx)) { + jsonw_list(ctx.jw, NULL); // wrap the json in a list, for syntactic correctness } thread_ctxs = calloc(ctx.n_threads, sizeof(*thread_ctxs)); threads = calloc(ctx.n_threads, sizeof(*threads)); if (thread_ctxs == NULL || threads == NULL) { ERR2("out of memory"); - free(thread_ctxs); - free(threads); - free_global_payloads(); - return EXIT_FAILURE; + goto err; } - for (int i = 0; i < ctx.n_threads; i++) { + for (uint32_t i = 0; i < ctx.n_threads; i++) { thread_ctxs[i] = ctx; thread_ctxs[i].thread_id = i; } @@ -1482,8 +1383,7 @@ int main(int argc, char *argv[]) cur_limit.rlim_max != min_limit.rlim_max) { int ret = setrlimit(RLIMIT_MEMLOCK, &min_limit); if (ret != 0) { - WARN2("unable to increase RLIMIT_MEMLOCK: %s", - strerror(errno)); + WARN2("unable to increase RLIMIT_MEMLOCK: %s", strerror(errno)); } } } @@ -1509,22 +1409,30 @@ int main(int argc, char *argv[]) usleep(20000); } usleep(1000000); - xdp_trigger = KXDPGUN_START; usleep(1000000); for (size_t i = 0; i < ctx.n_threads; i++) { pthread_join(threads[i], NULL); } - if (global_stats.duration > 0 && global_stats.qry_sent > 0) { - print_stats(&global_stats, ctx.tcp, ctx.quic, !(ctx.flags & KNOT_XDP_FILTER_DROP), ctx.qps * ctx.n_threads); + if (DURATION_US(global_stats) > 0 && global_stats.qry_sent > 0) { + if (!JSON_MODE(ctx)) { + puts(STATS_SECTION_SEP); + } + STATS_FMT(&ctx, &global_stats, STATS_SUM); } pthread_mutex_destroy(&global_stats.mutex); + ecode = EXIT_SUCCESS; + +err: free(ctx.rss_conf); free(thread_ctxs); free(threads); free_global_payloads(); - - return EXIT_SUCCESS; + if (JSON_MODE(ctx)) { + jsonw_end(ctx.jw); + jsonw_free(&ctx.jw); + } + return ecode; } diff --git a/src/utils/kxdpgun/main.h b/src/utils/kxdpgun/main.h new file mode 100644 index 0000000..d87aee8 --- /dev/null +++ b/src/utils/kxdpgun/main.h @@ -0,0 +1,87 @@ +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + 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 3 of the License, 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 <https://www.gnu.org/licenses/>. + */ + +#pragma once + +#include <net/if.h> +#include <netinet/in.h> +#include <stdbool.h> + +#include "contrib/json.h" +#include "libknot/xdp/eth.h" +#include "libknot/xdp/tcp.h" + +#define PROGRAM_NAME "kxdpgun" +#define SPACE " " + +#define REMOTE_PORT_DEFAULT 53 +#define REMOTE_PORT_DOQ_DEFAULT 853 +#define LOCAL_PORT_MIN 2000 +#define LOCAL_PORT_MAX 65535 +#define QUIC_THREAD_PORTS 100 + +enum { + KXDPGUN_WAIT, + KXDPGUN_START, + KXDPGUN_STOP, +}; + +typedef enum { + KXDPGUN_IGNORE_NONE = 0, + KXDPGUN_IGNORE_QUERY = (1 << 0), + KXDPGUN_IGNORE_LASTBYTE = (1 << 1), + KXDPGUN_IGNORE_CLOSE = (1 << 2), + KXDPGUN_REUSE_CONN = (1 << 3), +} xdp_gun_ignore_t; + +typedef struct xdp_gun_ctx { + union { + struct sockaddr_in local_ip4; + struct sockaddr_in6 local_ip; + struct sockaddr_storage local_ip_ss; + }; + union { + struct sockaddr_in target_ip4; + struct sockaddr_in6 target_ip; + struct sockaddr_storage target_ip_ss; + }; + char dev[IFNAMSIZ]; + uint64_t qps, duration; + uint64_t runid; + uint64_t stats_start_us; + uint32_t stats_period; // 0 means no periodic stats + unsigned at_once; + uint16_t msgid; + uint16_t edns_size; + uint16_t vlan_tci; + uint8_t local_mac[6], target_mac[6]; + uint8_t local_ip_range; + bool ipv6; + bool tcp; + bool quic; + bool quic_full_handshake; + const char *qlog_dir; + const char *sending_mode; + xdp_gun_ignore_t ignore1; + knot_tcp_ignore_t ignore2; + uint16_t target_port; + knot_xdp_filter_flag_t flags; + unsigned n_threads, thread_id; + knot_eth_rss_conf_t *rss_conf; + jsonw_t *jw; + char **argv; + knot_xdp_config_t xdp_config; +} xdp_gun_ctx_t; diff --git a/src/utils/kxdpgun/stats.c b/src/utils/kxdpgun/stats.c new file mode 100644 index 0000000..f1e4f43 --- /dev/null +++ b/src/utils/kxdpgun/stats.c @@ -0,0 +1,292 @@ +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + 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 3 of the License, 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 <https://www.gnu.org/licenses/>. + */ + +#include <assert.h> +#include <limits.h> +#include <pthread.h> +#include <stdlib.h> +#include <string.h> + +#include "contrib/macros.h" +#include "libknot/codes.h" +#include "libknot/lookup.h" +#include "utils/common/msg.h" +#include "utils/kxdpgun/main.h" +#include "utils/kxdpgun/stats.h" + +pthread_mutex_t stdout_mtx = PTHREAD_MUTEX_INITIALIZER; + +void clear_stats(kxdpgun_stats_t *st) +{ + pthread_mutex_lock(&st->mutex); + st->since = 0; + st->until = 0; + st->qry_sent = 0; + st->synack_recv = 0; + st->ans_recv = 0; + st->finack_recv = 0; + st->rst_recv = 0; + st->size_recv = 0; + st->wire_recv = 0; + st->collected = 0; + st->lost = 0; + st->errors = 0; + memset(st->rcodes_recv, 0, sizeof(st->rcodes_recv)); + pthread_mutex_unlock(&st->mutex); +} + +size_t collect_stats(kxdpgun_stats_t *into, const kxdpgun_stats_t *what) +{ + pthread_mutex_lock(&into->mutex); + into->since = what->since; + collect_periodic_stats(into, what); + size_t res = ++into->collected; + pthread_mutex_unlock(&into->mutex); + return res; +} + +void collect_periodic_stats(kxdpgun_stats_t *into, const kxdpgun_stats_t *what) +{ + into->until = what->until; + into->qry_sent += what->qry_sent; + into->synack_recv += what->synack_recv; + into->ans_recv += what->ans_recv; + into->finack_recv += what->finack_recv; + into->rst_recv += what->rst_recv; + into->size_recv += what->size_recv; + into->wire_recv += what->wire_recv; + into->lost += what->lost; + into->errors += what->errors; + for (int i = 0; i < RCODE_MAX; i++) { + into->rcodes_recv[i] += what->rcodes_recv[i]; + } +} + +void plain_stats_header(const xdp_gun_ctx_t *ctx) +{ + INFO2("using interface %s, XDP threads %u, IPv%c/%s%s%s, %s mode", ctx->dev, ctx->n_threads, + (ctx->ipv6 ? '6' : '4'), + (ctx->tcp ? "TCP" : ctx->quic ? "QUIC" : "UDP"), + (ctx->sending_mode[0] != '\0' ? " mode " : ""), + (ctx->sending_mode[0] != '\0' ? ctx->sending_mode : ""), + (knot_eth_xdp_mode(if_nametoindex(ctx->dev)) == KNOT_XDP_MODE_FULL ? "native" : "emulated")); + puts(STATS_SECTION_SEP); +} + +/* see: + * - https://github.com/DNS-OARC/dns-metrics/blob/main/dns-metrics.schema.json + * - https://github.com/DNS-OARC/dns-metrics/issues/16#issuecomment-2139462920 + */ +void json_stats_header(const xdp_gun_ctx_t *ctx) +{ + jsonw_t *w = ctx->jw; + + jsonw_object(w, NULL); + { + jsonw_ulong(w, "runid", ctx->runid); + jsonw_str(w, "type", "header"); + jsonw_int(w, "schema_version", STATS_SCHEMA_VERSION); + jsonw_str(w, "generator", PROGRAM_NAME); + jsonw_str(w, "generator_version", PACKAGE_VERSION); + + jsonw_list(w, "generator_params"); + { + for (char **it = ctx->argv; *it != NULL; ++it) { + jsonw_str(w, NULL, *it); + } + } + jsonw_end(w); + + jsonw_ulong(w, "time_units_per_sec", 1000000000); + if (ctx->stats_period > 0) { + jsonw_double(w, "stats_interval", ctx->stats_period / 1000.0); + } + // TODO: timeout + + // mirror the info given by the plaintext printout + jsonw_object(w, "additional_info"); + { + jsonw_str(w, "interface", ctx->dev); + jsonw_int(w, "xdp_threads", ctx->n_threads); + jsonw_int(w, "ip_version", ctx->ipv6 ? 6 : 4); + jsonw_str(w, "transport_layer_proto", ctx->tcp ? "TCP" : (ctx->quic ? "QUIC" : "UDP")); + jsonw_object(w, "mode_info"); + { + if (ctx->sending_mode[0] != '\0') { + jsonw_str(w, "debug", ctx->sending_mode); + } + jsonw_str(w, "mode", knot_eth_xdp_mode(if_nametoindex(ctx->dev)) == KNOT_XDP_MODE_FULL + ? "native" + : "emulated"); + } + jsonw_end(w); + } + jsonw_end(w); + } + jsonw_end(w); +} + +void plain_thrd_summary(const xdp_gun_ctx_t *ctx, const kxdpgun_stats_t *st) +{ + pthread_mutex_lock(&stdout_mtx); + + char recv_str[40] = "", lost_str[40] = "", err_str[40] = ""; + if (!(ctx->flags & KNOT_XDP_FILTER_DROP)) { + (void)snprintf(recv_str, sizeof(recv_str), ", received %"PRIu64, st->ans_recv); + } + if (st->lost > 0) { + (void)snprintf(lost_str, sizeof(lost_str), ", lost %"PRIu64, st->lost); + } + if (st->errors > 0) { + (void)snprintf(err_str, sizeof(err_str), ", errors %"PRIu64, st->errors); + } + INFO2("thread#%02u: sent %"PRIu64"%s%s%s", + ctx->thread_id, st->qry_sent, recv_str, lost_str, err_str); + + pthread_mutex_unlock(&stdout_mtx); +} + +void json_thrd_summary(const xdp_gun_ctx_t *ctx, const kxdpgun_stats_t *st) +{ + pthread_mutex_lock(&stdout_mtx); + + jsonw_t *w = ctx->jw; + + jsonw_object(ctx->jw, NULL); + { + jsonw_str(w, "type", "thread_summary"); + jsonw_ulong(w, "runid", ctx->runid); + jsonw_ulong(w, "subid", ctx->thread_id); + jsonw_ulong(w, "qry_sent", st->qry_sent); + jsonw_ulong(w, "ans_recv", st->ans_recv); + jsonw_ulong(w, "lost", st->lost); + jsonw_ulong(w, "errors", st->errors); + } + jsonw_end(ctx->jw); + + pthread_mutex_unlock(&stdout_mtx); +} + +void plain_stats(const xdp_gun_ctx_t *ctx, kxdpgun_stats_t *st, stats_type_t stt) +{ + pthread_mutex_lock(&st->mutex); + + printf("%s metrics:\n", (stt == STATS_SUM) ? "cumulative" : "periodic"); + + bool recv = !(ctx->flags & KNOT_XDP_FILTER_DROP); + uint64_t duration = DURATION_US(*st); + double rel_start_us = (st->since / 1000.0) - ctx->stats_start_us ; + double rel_end_us = rel_start_us + duration; + +#define ps(counter) ((typeof(counter))((counter) * 1000 / ((float)duration / 1000))) +#define pct(counter) ((counter) * 100.0 / st->qry_sent) + + const char *name = ctx->tcp ? "SYNs: " : ctx->quic ? "initials:" : "queries: "; + printf("total %s %"PRIu64" (%"PRIu64" pps) (%f%%)\n", name, st->qry_sent, + ps(st->qry_sent), 100.0 * st->qry_sent / (duration / 1000000.0 * ctx->qps * ctx->n_threads)); + if (st->qry_sent > 0 && recv) { + if (ctx->tcp || ctx->quic) { + name = ctx->tcp ? "established:" : "handshakes: "; + printf("total %s %"PRIu64" (%"PRIu64" pps) (%f%%)\n", name, + st->synack_recv, ps(st->synack_recv), pct(st->synack_recv)); + } + printf("total replies: %"PRIu64" (%"PRIu64" pps) (%f%%)\n", + st->ans_recv, ps(st->ans_recv), pct(st->ans_recv)); + if (ctx->tcp) { + printf("total closed: %"PRIu64" (%"PRIu64" pps) (%f%%)\n", + st->finack_recv, ps(st->finack_recv), pct(st->finack_recv)); + } + if (st->rst_recv > 0) { + printf("total reset: %"PRIu64" (%"PRIu64" pps) (%f%%)\n", + st->rst_recv, ps(st->rst_recv), pct(st->rst_recv)); + } + printf("average DNS reply size: %"PRIu64" B\n", + st->ans_recv > 0 ? st->size_recv / st->ans_recv : 0); + printf("average Ethernet reply rate: %"PRIu64" bps (%.2f Mbps)\n", + ps(st->wire_recv * 8), ps((float)st->wire_recv * 8 / (1000 * 1000))); + + for (int i = 0; i < RCODE_MAX; i++) { + if (st->rcodes_recv[i] > 0) { + const knot_lookup_t *rcode = knot_lookup_by_id(knot_rcode_names, i); + const char *rcname = rcode == NULL ? "unknown" : rcode->name; + int space = MAX(9 - strlen(rcname), 0); + printf("responded %s: %.*s%"PRIu64"\n", + rcname, space, " ", st->rcodes_recv[i]); + } + } + } + if (stt == STATS_SUM) { + printf("duration: %.4f s\n", duration / 1000000.0); + } else { + printf("since: %.4fs until: %.4fs\n", rel_start_us / 1000000, rel_end_us / 1000000); + } + + pthread_mutex_unlock(&st->mutex); +} + +/* see https://github.com/DNS-OARC/dns-metrics/blob/main/dns-metrics.schema.json + * and https://github.com/DNS-OARC/dns-metrics/issues/16#issuecomment-2139462920 */ +void json_stats(const xdp_gun_ctx_t *ctx, kxdpgun_stats_t *st, stats_type_t stt) +{ + assert(stt == STATS_PERIODIC || stt == STATS_SUM); + + jsonw_t *w = ctx->jw; + + pthread_mutex_lock(&st->mutex); + + jsonw_object(w, NULL); + { + jsonw_ulong(w, "runid", ctx->runid); + jsonw_str(w, "type", (stt == STATS_PERIODIC) ? "stats_periodic" : "stats_sum"); + jsonw_ulong(w, "since", st->since); + jsonw_ulong(w, "until", st->until); + jsonw_ulong(w, "queries", st->qry_sent); + jsonw_ulong(w, "responses", st->ans_recv); + + jsonw_object(w, "response_rcodes"); + { + for (size_t i = 0; i < RCODE_MAX; ++i) { + if (st->rcodes_recv[i] > 0) { + const knot_lookup_t *rc = knot_lookup_by_id(knot_rcode_names, i); + jsonw_ulong(w, (rc == NULL) ? "unknown" : rc->name, st->rcodes_recv[i]); + } + } + } + jsonw_end(w); + + jsonw_object(w, "conn_info"); + { + jsonw_str(w, "type", ctx->tcp ? "tcp" : (ctx->quic ? "quic_conn" : "udp")); + + // TODO: + // packets_sent + // packets_recieved + + jsonw_ulong(w, "socket_errors", st->errors); + if (ctx->tcp || ctx->quic) { + jsonw_ulong(w, "handshakes", st->synack_recv); + // TODO: handshakes_failed + if (ctx->quic) { + // TODO: conn_resumption + } + } + } + jsonw_end(w); + } + jsonw_end(w); + + pthread_mutex_unlock(&st->mutex); +} diff --git a/src/utils/kxdpgun/stats.h b/src/utils/kxdpgun/stats.h new file mode 100644 index 0000000..2c62ee3 --- /dev/null +++ b/src/utils/kxdpgun/stats.h @@ -0,0 +1,78 @@ +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + 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 3 of the License, 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 <https://www.gnu.org/licenses/>. + */ + +#pragma once + +#include <stddef.h> +#include <inttypes.h> +#include <pthread.h> +#include <stdbool.h> + +#include "utils/kxdpgun/main.h" + +#define RCODE_MAX (0x0F + 1) + +#define STATS_SECTION_SEP "--------------------------------------------------------------" + +#define JSON_INDENT " " +#define STATS_SCHEMA_VERSION 20240530 + +#define DURATION_US(st) (((st).until - (st).since) / 1000) +#define DURATION_NS(st) ((st).until - (st).since) + +#define JSON_MODE(ctx) ((ctx).jw != NULL) + +#define STATS_HDR(ctx) ((JSON_MODE(*(ctx)) ? json_stats_header : plain_stats_header)((ctx))) +#define STATS_THRD(ctx, stats) \ + ((JSON_MODE(*ctx) ? json_thrd_summary : plain_thrd_summary)((ctx), (stats))) +#define STATS_FMT(ctx, stats, stats_type) \ + ((JSON_MODE(*(ctx)) ? json_stats : plain_stats)((ctx), (stats), (stats_type))) + +typedef struct { + size_t collected; + uint64_t since, until; // nanosecs UNIX + uint64_t qry_sent; + uint64_t synack_recv; + uint64_t ans_recv; + uint64_t finack_recv; + uint64_t rst_recv; + uint64_t size_recv; + uint64_t wire_recv; + uint64_t errors; + uint64_t lost; + uint64_t rcodes_recv[RCODE_MAX]; + pthread_mutex_t mutex; +} kxdpgun_stats_t; + +typedef enum { + STATS_PERIODIC, + STATS_SUM, +} stats_type_t; + +void clear_stats(kxdpgun_stats_t *st); +size_t collect_stats(kxdpgun_stats_t *into, const kxdpgun_stats_t *what); +void collect_periodic_stats(kxdpgun_stats_t *into, const kxdpgun_stats_t *what); + +void plain_stats_header(const xdp_gun_ctx_t *ctx); +void json_stats_header(const xdp_gun_ctx_t *ctx); + +void plain_thrd_summary(const xdp_gun_ctx_t *ctx, const kxdpgun_stats_t *st); +void json_thrd_summary(const xdp_gun_ctx_t *ctx, const kxdpgun_stats_t *st); + +void plain_stats(const xdp_gun_ctx_t *ctx, kxdpgun_stats_t *st, stats_type_t stt); +void json_stats(const xdp_gun_ctx_t *ctx, kxdpgun_stats_t *st, stats_type_t stt); + +extern pthread_mutex_t stdout_mtx; diff --git a/src/utils/kzonecheck/main.c b/src/utils/kzonecheck/main.c index b602cc9..e8c5868 100644 --- a/src/utils/kzonecheck/main.c +++ b/src/utils/kzonecheck/main.c @@ -81,7 +81,7 @@ int main(int argc, char *argv[]) { "print", no_argument, NULL, 'p' }, { "verbose", no_argument, NULL, 'v' }, { "help", no_argument, NULL, 'h' }, - { "version", no_argument, NULL, 'V' }, + { "version", optional_argument, NULL, 'V' }, { NULL } }; @@ -90,7 +90,7 @@ int main(int argc, char *argv[]) /* Parse command line arguments */ int opt = 0; - while ((opt = getopt_long(argc, argv, "o:t:d:zpvVh", opts, NULL)) != -1) { + while ((opt = getopt_long(argc, argv, "o:t:d:zpvV::h", opts, NULL)) != -1) { switch (opt) { case 'o': origin = optarg; @@ -105,7 +105,7 @@ int main(int argc, char *argv[]) print_help(); return EXIT_SUCCESS; case 'V': - print_version(PROGRAM_NAME); + print_version(PROGRAM_NAME, optarg != NULL); return EXIT_SUCCESS; case 'd': optional = str2bool(optarg) ? SEMCHECK_DNSSEC_ON : SEMCHECK_DNSSEC_OFF; diff --git a/src/utils/kzonesign/main.c b/src/utils/kzonesign/main.c index e70abb6..641acfc 100644 --- a/src/utils/kzonesign/main.c +++ b/src/utils/kzonesign/main.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -117,7 +117,7 @@ static int zonesign(sign_params_t *params) goto fail; } - ret = knot_dnssec_validate_zone(&up, conf(), params->timestamp, false); + ret = knot_dnssec_validate_zone(&up, conf(), params->timestamp, false, false); if (ret != KNOT_EOK) { ERR2("DNSSEC validation failed (%s)", knot_strerror(ret)); char type_str[16]; @@ -204,7 +204,7 @@ int main(int argc, char *argv[]) { "verify" , no_argument, NULL, 'v' }, { "time", required_argument, NULL, 't' }, { "help", no_argument, NULL, 'h' }, - { "version", no_argument, NULL, 'V' }, + { "version", optional_argument, NULL, 'V' }, { NULL } }; @@ -212,7 +212,7 @@ int main(int argc, char *argv[]) signal_init_std(); int opt = 0; - while ((opt = getopt_long(argc, argv, "c:C:o:rvt:hV", opts, NULL)) != -1) { + while ((opt = getopt_long(argc, argv, "c:C:o:rvt:hV::", opts, NULL)) != -1) { switch (opt) { case 'c': if (util_conf_init_file(optarg) != KNOT_EOK) { @@ -245,7 +245,7 @@ int main(int argc, char *argv[]) print_help(); goto success; case 'V': - print_version(PROGRAM_NAME); + print_version(PROGRAM_NAME, optarg != NULL); goto success; default: print_help(); diff --git a/tests-fuzz/Makefile.am b/tests-fuzz/Makefile.am index dcf18a6..489153d 100644 --- a/tests-fuzz/Makefile.am +++ b/tests-fuzz/Makefile.am @@ -31,7 +31,8 @@ knotd_stdio_CPPFLAGS = \ $(libkqueue_CFLAGS) \ $(liburcu_CFLAGS) \ $(lmdb_CFLAGS) \ - $(systemd_CFLAGS) + $(systemd_CFLAGS) \ + $(libdbus_CFLAGS) knotd_stdio_LDADD = \ $(top_builddir)/src/libknotd.la \ @@ -43,7 +44,8 @@ knotd_stdio_LDADD = \ $(gnutls_LIBS) \ $(liburcu_LIBS) \ $(lmdb_LIBS) \ - $(systemd_LIBS) + $(systemd_LIBS) \ + $(libdbus_LIBS) BUILT_SOURCES = knotd_wrap/main.c CLEANFILES = knotd_wrap/main.c diff --git a/tests-fuzz/Makefile.in b/tests-fuzz/Makefile.in index 7c94673..55650c4 100644 --- a/tests-fuzz/Makefile.in +++ b/tests-fuzz/Makefile.in @@ -205,7 +205,7 @@ knotd_stdio_OBJECTS = $(am_knotd_stdio_OBJECTS) \ @HAVE_DAEMON_TRUE@ $(top_builddir)/src/libzscanner.la \ @HAVE_DAEMON_TRUE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ @HAVE_DAEMON_TRUE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ -@HAVE_DAEMON_TRUE@ $(am__DEPENDENCIES_1) +@HAVE_DAEMON_TRUE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false @@ -623,6 +623,8 @@ infodir = @infodir@ install_sh = @install_sh@ libbpf_CFLAGS = @libbpf_CFLAGS@ libbpf_LIBS = @libbpf_LIBS@ +libdbus_CFLAGS = @libdbus_CFLAGS@ +libdbus_LIBS = @libdbus_LIBS@ libdir = @libdir@ libdnssec_SONAME = @libdnssec_SONAME@ libdnssec_SOVERSION = @libdnssec_SOVERSION@ @@ -634,8 +636,6 @@ libfstrm_CFLAGS = @libfstrm_CFLAGS@ libfstrm_LIBS = @libfstrm_LIBS@ libidn2_CFLAGS = @libidn2_CFLAGS@ libidn2_LIBS = @libidn2_LIBS@ -libidn_CFLAGS = @libidn_CFLAGS@ -libidn_LIBS = @libidn_LIBS@ libknot_SONAME = @libknot_SONAME@ libknot_SOVERSION = @libknot_SOVERSION@ libknot_VERSION_INFO = @libknot_VERSION_INFO@ @@ -653,7 +653,6 @@ libprotobuf_c_CFLAGS = @libprotobuf_c_CFLAGS@ libprotobuf_c_LIBS = @libprotobuf_c_LIBS@ liburcu_CFLAGS = @liburcu_CFLAGS@ liburcu_LIBS = @liburcu_LIBS@ -liburcu_PKGCONFIG = @liburcu_PKGCONFIG@ libxdp_CFLAGS = @libxdp_CFLAGS@ libxdp_LIBS = @libxdp_LIBS@ libzscanner_SONAME = @libzscanner_SONAME@ @@ -715,7 +714,8 @@ FUZZERS = \ @HAVE_DAEMON_TRUE@ $(libkqueue_CFLAGS) \ @HAVE_DAEMON_TRUE@ $(liburcu_CFLAGS) \ @HAVE_DAEMON_TRUE@ $(lmdb_CFLAGS) \ -@HAVE_DAEMON_TRUE@ $(systemd_CFLAGS) +@HAVE_DAEMON_TRUE@ $(systemd_CFLAGS) \ +@HAVE_DAEMON_TRUE@ $(libdbus_CFLAGS) @HAVE_DAEMON_TRUE@knotd_stdio_LDADD = \ @HAVE_DAEMON_TRUE@ $(top_builddir)/src/libknotd.la \ @@ -727,7 +727,8 @@ FUZZERS = \ @HAVE_DAEMON_TRUE@ $(gnutls_LIBS) \ @HAVE_DAEMON_TRUE@ $(liburcu_LIBS) \ @HAVE_DAEMON_TRUE@ $(lmdb_LIBS) \ -@HAVE_DAEMON_TRUE@ $(systemd_LIBS) +@HAVE_DAEMON_TRUE@ $(systemd_LIBS) \ +@HAVE_DAEMON_TRUE@ $(libdbus_LIBS) @HAVE_DAEMON_TRUE@BUILT_SOURCES = knotd_wrap/main.c @HAVE_DAEMON_TRUE@CLEANFILES = knotd_wrap/main.c diff --git a/tests/Makefile.am b/tests/Makefile.am index c173b61..bbcf8b8 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -14,7 +14,8 @@ if HAVE_DAEMON LDADD += \ $(top_builddir)/src/libknotd.la \ $(liburcu_LIBS) \ - $(systemd_LIBS) + $(systemd_LIBS) \ + $(libdbus_LIBS) endif HAVE_DAEMON LDADD += \ @@ -47,6 +48,7 @@ libtap_la_SOURCES = \ EXTRA_PROGRAMS = tap/runtests check_PROGRAMS = \ + contrib/test_atomic \ contrib/test_base32hex \ contrib/test_base64 \ contrib/test_base64url \ diff --git a/tests/Makefile.in b/tests/Makefile.in index 3170082..b0c576a 100644 --- a/tests/Makefile.in +++ b/tests/Makefile.in @@ -90,14 +90,16 @@ host_triplet = @host@ @HAVE_DAEMON_TRUE@am__append_1 = \ @HAVE_DAEMON_TRUE@ $(top_builddir)/src/libknotd.la \ @HAVE_DAEMON_TRUE@ $(liburcu_LIBS) \ -@HAVE_DAEMON_TRUE@ $(systemd_LIBS) +@HAVE_DAEMON_TRUE@ $(systemd_LIBS) \ +@HAVE_DAEMON_TRUE@ $(libdbus_LIBS) EXTRA_PROGRAMS = tap/runtests$(EXEEXT) \ libzscanner/zscanner-tool$(EXEEXT) -check_PROGRAMS = contrib/test_base32hex$(EXEEXT) \ - contrib/test_base64$(EXEEXT) contrib/test_base64url$(EXEEXT) \ - contrib/test_heap$(EXEEXT) contrib/test_inet_ntop$(EXEEXT) \ - contrib/test_net$(EXEEXT) contrib/test_net_shortwrite$(EXEEXT) \ +check_PROGRAMS = contrib/test_atomic$(EXEEXT) \ + contrib/test_base32hex$(EXEEXT) contrib/test_base64$(EXEEXT) \ + contrib/test_base64url$(EXEEXT) contrib/test_heap$(EXEEXT) \ + contrib/test_inet_ntop$(EXEEXT) contrib/test_net$(EXEEXT) \ + contrib/test_net_shortwrite$(EXEEXT) \ contrib/test_qp-trie$(EXEEXT) contrib/test_qp-cow$(EXEEXT) \ contrib/test_siphash$(EXEEXT) contrib/test_sockaddr$(EXEEXT) \ contrib/test_spinlock$(EXEEXT) contrib/test_string$(EXEEXT) \ @@ -236,13 +238,23 @@ 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 = -contrib_test_base32hex_SOURCES = contrib/test_base32hex.c -contrib_test_base32hex_OBJECTS = contrib/test_base32hex.$(OBJEXT) -contrib_test_base32hex_LDADD = $(LDADD) +contrib_test_atomic_SOURCES = contrib/test_atomic.c +contrib_test_atomic_OBJECTS = contrib/test_atomic.$(OBJEXT) +contrib_test_atomic_LDADD = $(LDADD) am__DEPENDENCIES_1 = @HAVE_DAEMON_TRUE@am__DEPENDENCIES_2 = \ @HAVE_DAEMON_TRUE@ $(top_builddir)/src/libknotd.la \ -@HAVE_DAEMON_TRUE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) +@HAVE_DAEMON_TRUE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ +@HAVE_DAEMON_TRUE@ $(am__DEPENDENCIES_1) +contrib_test_atomic_DEPENDENCIES = libtap.la $(am__DEPENDENCIES_2) \ + $(top_builddir)/src/libknot.la \ + $(top_builddir)/src/libdnssec.la \ + $(top_builddir)/src/libcontrib.la \ + $(top_builddir)/src/libzscanner.la $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) +contrib_test_base32hex_SOURCES = contrib/test_base32hex.c +contrib_test_base32hex_OBJECTS = contrib/test_base32hex.$(OBJEXT) +contrib_test_base32hex_LDADD = $(LDADD) contrib_test_base32hex_DEPENDENCIES = libtap.la $(am__DEPENDENCIES_2) \ $(top_builddir)/src/libknot.la \ $(top_builddir)/src/libdnssec.la \ @@ -1058,7 +1070,8 @@ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/src depcomp = $(SHELL) $(top_srcdir)/depcomp am__maybe_remake_depfiles = depfiles -am__depfiles_remade = contrib/$(DEPDIR)/test_base32hex.Po \ +am__depfiles_remade = contrib/$(DEPDIR)/test_atomic.Po \ + contrib/$(DEPDIR)/test_base32hex.Po \ contrib/$(DEPDIR)/test_base64.Po \ contrib/$(DEPDIR)/test_base64url.Po \ contrib/$(DEPDIR)/test_heap.Po \ @@ -1155,20 +1168,21 @@ 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 = $(libtap_la_SOURCES) contrib/test_base32hex.c \ - contrib/test_base64.c contrib/test_base64url.c \ - contrib/test_heap.c contrib/test_inet_ntop.c \ - contrib/test_net.c contrib/test_net_shortwrite.c \ - contrib/test_qp-cow.c contrib/test_qp-trie.c \ - contrib/test_siphash.c contrib/test_sockaddr.c \ - contrib/test_spinlock.c contrib/test_string.c \ - contrib/test_strtonum.c contrib/test_time.c \ - contrib/test_toeplitz.c contrib/test_wire_ctx.c \ - $(knot_test_acl_SOURCES) knot/test_changeset.c \ - $(knot_test_conf_SOURCES) knot/test_conf_tools.c \ - $(knot_test_confdb_SOURCES) $(knot_test_confio_SOURCES) \ - knot/test_digest.c knot/test_dthreads.c knot/test_fdset.c \ - knot/test_journal.c knot/test_kasp_db.c knot/test_node.c \ +SOURCES = $(libtap_la_SOURCES) contrib/test_atomic.c \ + contrib/test_base32hex.c contrib/test_base64.c \ + contrib/test_base64url.c contrib/test_heap.c \ + contrib/test_inet_ntop.c contrib/test_net.c \ + contrib/test_net_shortwrite.c contrib/test_qp-cow.c \ + contrib/test_qp-trie.c contrib/test_siphash.c \ + contrib/test_sockaddr.c contrib/test_spinlock.c \ + contrib/test_string.c contrib/test_strtonum.c \ + contrib/test_time.c contrib/test_toeplitz.c \ + contrib/test_wire_ctx.c $(knot_test_acl_SOURCES) \ + knot/test_changeset.c $(knot_test_conf_SOURCES) \ + knot/test_conf_tools.c $(knot_test_confdb_SOURCES) \ + $(knot_test_confio_SOURCES) knot/test_digest.c \ + knot/test_dthreads.c knot/test_fdset.c knot/test_journal.c \ + knot/test_kasp_db.c knot/test_node.c \ $(knot_test_process_query_SOURCES) knot/test_query_module.c \ knot/test_requestor.c knot/test_server.c \ knot/test_unreachable.c knot/test_worker_pool.c \ @@ -1197,18 +1211,18 @@ SOURCES = $(libtap_la_SOURCES) contrib/test_base32hex.c \ libknot/test_yptrafo.c $(libzscanner_zscanner_tool_SOURCES) \ modules/test_onlinesign.c modules/test_rrl.c tap/runtests.c \ utils/test_lookup.c -DIST_SOURCES = $(libtap_la_SOURCES) contrib/test_base32hex.c \ - contrib/test_base64.c contrib/test_base64url.c \ - contrib/test_heap.c contrib/test_inet_ntop.c \ - contrib/test_net.c contrib/test_net_shortwrite.c \ - contrib/test_qp-cow.c contrib/test_qp-trie.c \ - contrib/test_siphash.c contrib/test_sockaddr.c \ - contrib/test_spinlock.c contrib/test_string.c \ - contrib/test_strtonum.c contrib/test_time.c \ - contrib/test_toeplitz.c contrib/test_wire_ctx.c \ - $(am__knot_test_acl_SOURCES_DIST) knot/test_changeset.c \ - $(am__knot_test_conf_SOURCES_DIST) knot/test_conf_tools.c \ - $(am__knot_test_confdb_SOURCES_DIST) \ +DIST_SOURCES = $(libtap_la_SOURCES) contrib/test_atomic.c \ + contrib/test_base32hex.c contrib/test_base64.c \ + contrib/test_base64url.c contrib/test_heap.c \ + contrib/test_inet_ntop.c contrib/test_net.c \ + contrib/test_net_shortwrite.c contrib/test_qp-cow.c \ + contrib/test_qp-trie.c contrib/test_siphash.c \ + contrib/test_sockaddr.c contrib/test_spinlock.c \ + contrib/test_string.c contrib/test_strtonum.c \ + contrib/test_time.c contrib/test_toeplitz.c \ + contrib/test_wire_ctx.c $(am__knot_test_acl_SOURCES_DIST) \ + knot/test_changeset.c $(am__knot_test_conf_SOURCES_DIST) \ + knot/test_conf_tools.c $(am__knot_test_confdb_SOURCES_DIST) \ $(am__knot_test_confio_SOURCES_DIST) knot/test_digest.c \ knot/test_dthreads.c knot/test_fdset.c knot/test_journal.c \ knot/test_kasp_db.c knot/test_node.c \ @@ -1397,6 +1411,8 @@ infodir = @infodir@ install_sh = @install_sh@ libbpf_CFLAGS = @libbpf_CFLAGS@ libbpf_LIBS = @libbpf_LIBS@ +libdbus_CFLAGS = @libdbus_CFLAGS@ +libdbus_LIBS = @libdbus_LIBS@ libdir = @libdir@ libdnssec_SONAME = @libdnssec_SONAME@ libdnssec_SOVERSION = @libdnssec_SOVERSION@ @@ -1408,8 +1424,6 @@ libfstrm_CFLAGS = @libfstrm_CFLAGS@ libfstrm_LIBS = @libfstrm_LIBS@ libidn2_CFLAGS = @libidn2_CFLAGS@ libidn2_LIBS = @libidn2_LIBS@ -libidn_CFLAGS = @libidn_CFLAGS@ -libidn_LIBS = @libidn_LIBS@ libknot_SONAME = @libknot_SONAME@ libknot_SOVERSION = @libknot_SOVERSION@ libknot_VERSION_INFO = @libknot_VERSION_INFO@ @@ -1427,7 +1441,6 @@ libprotobuf_c_CFLAGS = @libprotobuf_c_CFLAGS@ libprotobuf_c_LIBS = @libprotobuf_c_LIBS@ liburcu_CFLAGS = @liburcu_CFLAGS@ liburcu_LIBS = @liburcu_LIBS@ -liburcu_PKGCONFIG = @liburcu_PKGCONFIG@ libxdp_CFLAGS = @libxdp_CFLAGS@ libxdp_LIBS = @libxdp_LIBS@ libzscanner_SONAME = @libzscanner_SONAME@ @@ -1609,6 +1622,12 @@ contrib/$(am__dirstamp): contrib/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) contrib/$(DEPDIR) @: > contrib/$(DEPDIR)/$(am__dirstamp) +contrib/test_atomic.$(OBJEXT): contrib/$(am__dirstamp) \ + contrib/$(DEPDIR)/$(am__dirstamp) + +contrib/test_atomic$(EXEEXT): $(contrib_test_atomic_OBJECTS) $(contrib_test_atomic_DEPENDENCIES) $(EXTRA_contrib_test_atomic_DEPENDENCIES) contrib/$(am__dirstamp) + @rm -f contrib/test_atomic$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(contrib_test_atomic_OBJECTS) $(contrib_test_atomic_LDADD) $(LIBS) contrib/test_base32hex.$(OBJEXT): contrib/$(am__dirstamp) \ contrib/$(DEPDIR)/$(am__dirstamp) @@ -2179,6 +2198,7 @@ mostlyclean-compile: distclean-compile: -rm -f *.tab.c +@AMDEP_TRUE@@am__include@ @am__quote@contrib/$(DEPDIR)/test_atomic.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@contrib/$(DEPDIR)/test_base32hex.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@contrib/$(DEPDIR)/test_base64.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@contrib/$(DEPDIR)/test_base64url.Po@am__quote@ # am--include-marker @@ -2486,7 +2506,8 @@ clean-am: clean-checkLTLIBRARIES clean-checkPROGRAMS clean-generic \ clean-libtool mostlyclean-am distclean: distclean-am - -rm -f contrib/$(DEPDIR)/test_base32hex.Po + -rm -f contrib/$(DEPDIR)/test_atomic.Po + -rm -f contrib/$(DEPDIR)/test_base32hex.Po -rm -f contrib/$(DEPDIR)/test_base64.Po -rm -f contrib/$(DEPDIR)/test_base64url.Po -rm -f contrib/$(DEPDIR)/test_heap.Po @@ -2621,7 +2642,8 @@ install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am - -rm -f contrib/$(DEPDIR)/test_base32hex.Po + -rm -f contrib/$(DEPDIR)/test_atomic.Po + -rm -f contrib/$(DEPDIR)/test_base32hex.Po -rm -f contrib/$(DEPDIR)/test_base64.Po -rm -f contrib/$(DEPDIR)/test_base64url.Po -rm -f contrib/$(DEPDIR)/test_heap.Po diff --git a/tests/contrib/test_atomic.c b/tests/contrib/test_atomic.c new file mode 100644 index 0000000..88cae40 --- /dev/null +++ b/tests/contrib/test_atomic.c @@ -0,0 +1,165 @@ +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + 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 3 of the License, 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 <https://www.gnu.org/licenses/>. + */ + +#include <pthread.h> +#include <signal.h> +#include <tap/basic.h> + +#include "contrib/atomic.h" +#include "knot/server/dthreads.h" + +#define THREADS 16 +#define CYCLES1 100000 +#define CYCLES2 2000000 +#define CYCLES3 100000 +#define UPPER 0xffffffff00000000 +#define LOWER 0x00000000ffffffff +#define UPPER_PTR ((void *) UPPER) +#define LOWER_PTR ((void *) LOWER) + +static volatile knot_atomic_uint64_t counter_add = 0; +static volatile knot_atomic_uint64_t counter_sub = 0; +static volatile knot_atomic_uint64_t atomic_var; +static volatile knot_atomic_ptr_t atomic_var2; +static int errors = 0; +static int uppers; +static int lowers; +static int uppers_count = 0; +static int lowers_count = 0; +static pthread_mutex_t mx; + +static int thread_add(struct dthread *thread) +{ + for (int i = 0; i < CYCLES1; i++) { + ATOMIC_ADD(counter_add, 7); + ATOMIC_SUB(counter_sub, 7); + } + + return 0; +} + +static int thread_set(struct dthread *thread) +{ + u_int64_t val = (dt_get_id(thread) % 2) ? UPPER : LOWER; + + for (int i = 0; i < CYCLES2; i++) { + ATOMIC_SET(atomic_var, val); + volatile u_int64_t read = ATOMIC_GET(atomic_var); + if (read != UPPER && read != LOWER) { + // Non-atomic counter, won't be accurate! + // However, it's sufficient for fault detection. + errors++; + } + } + + return 0; +} + +static int thread_xchg(struct dthread *thread) +{ + void *val = (dt_get_id(thread) % 2) ? UPPER_PTR : LOWER_PTR; + + pthread_mutex_lock(&mx); + if (val == UPPER_PTR) { + uppers++; + } else { + lowers++; + }; + pthread_mutex_unlock(&mx); + + for (int i = 0; i < CYCLES3; i++) { + val = ATOMIC_XCHG(atomic_var2, val); + if (val != UPPER_PTR && val != LOWER_PTR) { + // Non-atomic counter, won't be accurate! + // However, it's sufficient for fault detection. + errors++; + return 0; + } + } + + pthread_mutex_lock(&mx); + if (val == UPPER_PTR) { + uppers_count++; + } else if (val == LOWER_PTR) { + lowers_count++; + }; + pthread_mutex_unlock(&mx); + + return 0; +} + +// Signal handler +static void interrupt_handle(int s) +{ +} + +int main(int argc, char *argv[]) +{ + plan_lazy(); + + // Register service and signal handler + struct sigaction sa; + sa.sa_handler = interrupt_handle; + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + sigaction(SIGALRM, &sa, NULL); // Interrupt + + // Test for atomicity of ATOMIC_ADD and ATOMIC_SUB. + dt_unit_t *unit = dt_create(THREADS, thread_add, NULL, NULL); + dt_start(unit); + dt_join(unit); + dt_delete(&unit); + + is_int(THREADS * CYCLES1 * 7, counter_add, "atomicity of ATOMIC_ADD"); + is_int(THREADS * CYCLES1 * 7, -counter_sub, "atomicity of ATOMIC_SUB"); + + // Test for atomicity of ATOMIC_SET and ATOMIC_GET. + unit = dt_create(THREADS, thread_set, NULL, NULL); + dt_start(unit); + dt_join(unit); + dt_delete(&unit); + + is_int(0, errors, "atomicity of ATOMIC_SET / ATOMIC_GET"); + + // Test for atomicity of ATOMIC_XCHG. + errors = 0; + uppers = 0; // Initialize in code so as to calm down Coverity. + lowers = 0; // Idem. + + atomic_var2 = UPPER_PTR; + uppers++; + + pthread_mutex_init(&mx, NULL); + unit = dt_create(THREADS, thread_xchg, NULL, NULL); + dt_start(unit); + dt_join(unit); + dt_delete(&unit); + pthread_mutex_destroy(&mx); + + if (atomic_var2 == UPPER_PTR) { + uppers_count++; + } else if (atomic_var2 == LOWER_PTR) { + lowers_count++; + } else { + errors++; + } + + is_int(0, errors, "set/get atomicity of ATOMIC_XCHG"); + is_int(uppers, uppers_count, "atomicity of ATOMIC_XCHG"); + is_int(lowers, lowers_count, "atomicity of ATOMIC_XCHG"); + + return 0; +} diff --git a/tests/knot/semantic_check_data/soa.duplicate b/tests/knot/semantic_check_data/soa.duplicate new file mode 100644 index 0000000..8b84745 --- /dev/null +++ b/tests/knot/semantic_check_data/soa.duplicate @@ -0,0 +1,5 @@ +$ORIGIN example.com. + +@ SOA dns1 hostmaster 1 1000 360 10000 7200 +@ NS example.net. +@ SOA dns1 hostmaster 1 1000 360 10000 7200 diff --git a/tests/knot/semantic_check_data/soa.missing b/tests/knot/semantic_check_data/soa.missing new file mode 100644 index 0000000..cda9e84 --- /dev/null +++ b/tests/knot/semantic_check_data/soa.missing @@ -0,0 +1,3 @@ +$ORIGIN example.com. + +@ NS example.net. diff --git a/tests/knot/semantic_check_data/soa.multiple b/tests/knot/semantic_check_data/soa.multiple new file mode 100644 index 0000000..f41485c --- /dev/null +++ b/tests/knot/semantic_check_data/soa.multiple @@ -0,0 +1,5 @@ +$ORIGIN example.com. + +@ SOA dns1 hostmaster 1 1000 360 10000 7200 +@ NS example.net. +@ SOA dns1 hostmaster 2 1000 360 10000 7200 diff --git a/tests/knot/test_confdb.c b/tests/knot/test_confdb.c index e149f8d..28e4e0e 100644 --- a/tests/knot/test_confdb.c +++ b/tests/knot/test_confdb.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -392,7 +392,7 @@ static void test_conf_db_unset(conf_t *conf, knot_db_txn_t *txn) // Unset multivalued item with id - all data at one step (non-null data!). check_unset(conf, txn, C_ZONE, C_MASTER, (uint8_t *)"id", 2, KNOT_EOK, - NULL + 1, 0, NULL, 0); + (void *)8, 0, NULL, 0); // Unset group id. check_unset(conf, txn, C_ZONE, NULL, (uint8_t *)"id", 2, KNOT_EOK, diff --git a/tests/knot/test_confio.c b/tests/knot/test_confio.c index 44bc7c5..07bad05 100644 --- a/tests/knot/test_confio.c +++ b/tests/knot/test_confio.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -999,7 +999,7 @@ static const yp_item_t desc_server[] = { static const yp_item_t desc_xdp[] = { { C_UDP, YP_TBOOL, YP_VNONE }, { C_TCP, YP_TBOOL, YP_VNONE }, - { C_QUIC, YP_TBOOL, YP_VNONE }, + { C_QUIC, YP_TBOOL, YP_VNONE }, { C_TCP_MAX_CLIENTS, YP_TINT, YP_VNONE }, { C_TCP_INBUF_MAX_SIZE, YP_TINT, YP_VNONE }, { C_TCP_OUTBUF_MAX_SIZE,YP_TINT, YP_VNONE }, @@ -1007,6 +1007,9 @@ static const yp_item_t desc_xdp[] = { { C_TCP_IDLE_RESET, YP_TINT, YP_VNONE }, { C_TCP_RESEND, YP_TINT, YP_VNONE }, { C_ROUTE_CHECK, YP_TBOOL, YP_VNONE }, + { C_RING_SIZE, YP_TINT, YP_VNONE }, + { C_BUSYPOLL_BUDGET, YP_TINT, YP_VNONE }, + { C_BUSYPOLL_TIMEOUT, YP_TINT, YP_VNONE }, { NULL } }; diff --git a/tests/knot/test_query_module.c b/tests/knot/test_query_module.c index 4ab14d2..d31fa7c 100644 --- a/tests/knot/test_query_module.c +++ b/tests/knot/test_query_module.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -20,11 +20,10 @@ #include "libknot/libknot.h" #include "knot/nameserver/query_module.h" -#include "libknot/packet/pkt.h" /* Universal processing stage. */ -unsigned state_visit(unsigned state, knot_pkt_t *pkt, knotd_qdata_t *qdata, - knotd_mod_t *mod) +knotd_state_t state_visit(knotd_state_t state, knot_pkt_t *pkt, knotd_qdata_t *qdata, + knotd_mod_t *mod) { /* Visit current state */ bool *state_map = (bool *)mod; @@ -49,8 +48,8 @@ int main(int argc, char *argv[]) /* Register all stage visits. */ int ret = KNOT_EOK; - for (unsigned stage = KNOTD_STAGE_BEGIN; stage < KNOTD_STAGES; ++stage) { - ret = query_plan_step(plan, stage, state_visit, state_map); + for (unsigned stage = KNOTD_STAGE_PROTO_BEGIN; stage < KNOTD_STAGES; ++stage) { + ret = query_plan_step(plan, stage, QUERY_HOOK_TYPE_GENERAL, state_visit, state_map); if (ret != KNOT_EOK) { break; } @@ -59,10 +58,10 @@ int main(int argc, char *argv[]) /* Execute the plan. */ int state = 0, next_state = 0; - for (unsigned stage = KNOTD_STAGE_BEGIN; stage < KNOTD_STAGES; ++stage) { + for (unsigned stage = KNOTD_STAGE_PROTO_BEGIN; stage < KNOTD_STAGES; ++stage) { struct query_step *step = NULL; WALK_LIST(step, plan->stage[stage]) { - next_state = step->process(state, NULL, NULL, step->ctx); + next_state = step->general_hook(state, NULL, NULL, step->ctx); if (next_state != state + 1) { break; } diff --git a/tests/knot/test_semantic_check.in b/tests/knot/test_semantic_check.in index 73fb6e7..e91e9dc 100644 --- a/tests/knot/test_semantic_check.in +++ b/tests/knot/test_semantic_check.in @@ -48,6 +48,8 @@ if [ ! -x $KZONECHECK ]; then fi # error messages exported from knot/src/zone/semantic-check.c +SOA_NONE="missing SOA at the zone apex" +SOA_MULTIPLE="multiple SOA records" CDNSKEY_NONE="missing CDNSKEY" CDNSKEY_NO_CDS="CDNSKEY without corresponding CDS" CDNSKEY_DELETE="invalid CDNSKEY/CDS for DNSSEC delete algorithm" @@ -74,6 +76,8 @@ RRSIG_UNVERIFIABLE="no valid signature for a record" plan_lazy +expect_error "soa.missing" 1 1 "$SOA_MISSING" +expect_error "soa.multiple" 1 1 "$SOA_MULTIPLE" expect_error "cname_extra_01.zone" 1 1 "$CNAME_EXTRA_RECORDS" expect_error "cname_extra_02.signed" 1 1 "$CNAME_EXTRA_RECORDS" expect_error "cname_multiple.zone" 1 1 "$CNAME_MULTIPLE" @@ -127,6 +131,7 @@ expect_error "cdnskey.delete.invalid.cdnskey" 0 1 "$CDNSKEY_DELETE" expect_error "delegation.signed" 0 1 "$NSEC_RDATA_BITMAP" expect_error "nsec_nonauth.invalid" 0 1 "$NSEC_EXTRA" +test_correct "soa.duplicate" test_correct "rrsig_ttl.signed" test_correct "no_error_delegation_bitmap.signed" test_correct "no_error_nsec3_optout.signed" diff --git a/tests/libdnssec/test_key.c b/tests/libdnssec/test_key.c index 4f05405..effbe1a 100644 --- a/tests/libdnssec/test_key.c +++ b/tests/libdnssec/test_key.c @@ -192,9 +192,7 @@ int main(void) static const keyinfo_t keys[] = { { "RSA", &SAMPLE_RSA_KEY }, { "ECDSA", &SAMPLE_ECDSA_KEY }, -#ifdef HAVE_ED25519 { "ED25519", &SAMPLE_ED25519_KEY }, -#endif #ifdef HAVE_ED448 { "ED448", &SAMPLE_ED448_KEY }, #endif diff --git a/tests/libdnssec/test_key_algorithm.c b/tests/libdnssec/test_key_algorithm.c index 6c62106..75eace7 100644 --- a/tests/libdnssec/test_key_algorithm.c +++ b/tests/libdnssec/test_key_algorithm.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -59,9 +59,7 @@ static void check_defaults(void) { is_int(2048, dnssec_algorithm_key_size_default(DNSSEC_KEY_ALGORITHM_RSA_SHA1_NSEC3), "rsa default"); is_int(256, dnssec_algorithm_key_size_default(DNSSEC_KEY_ALGORITHM_ECDSA_P256_SHA256), "ecc default"); -#ifdef HAVE_ED25519 is_int(256, dnssec_algorithm_key_size_default(DNSSEC_KEY_ALGORITHM_ED25519), "ed25519 default"); -#endif #ifdef HAVE_ED448 is_int(456, dnssec_algorithm_key_size_default(DNSSEC_KEY_ALGORITHM_ED448), "ed448 default"); #endif @@ -74,9 +72,7 @@ int main(void) // ranges ok_range(DNSSEC_KEY_ALGORITHM_RSA_SHA512, 1024, 4096, "RSA/SHA256"); ok_range(DNSSEC_KEY_ALGORITHM_ECDSA_P384_SHA384, 384, 384, "ECDSA/SHA384"); -#ifdef HAVE_ED25519 ok_range(DNSSEC_KEY_ALGORITHM_ED25519, 256, 256, "ED25519"); -#endif #ifdef HAVE_ED448 ok_range(DNSSEC_KEY_ALGORITHM_ED448, 456, 456, "ED448"); #endif diff --git a/tests/libdnssec/test_key_ds.c b/tests/libdnssec/test_key_ds.c index 29acf05..e076243 100644 --- a/tests/libdnssec/test_key_ds.c +++ b/tests/libdnssec/test_key_ds.c @@ -101,17 +101,13 @@ int main(int argc, char *argv[]) test_key("RSA", &SAMPLE_RSA_KEY); test_key("ECDSA", &SAMPLE_ECDSA_KEY); -#ifdef HAVE_ED25519 test_key("ED25519", &SAMPLE_ED25519_KEY); -#endif #ifdef HAVE_ED448 test_key("ED448", &SAMPLE_ED448_KEY); #endif test_errors(&SAMPLE_ECDSA_KEY); -#ifdef HAVE_ED25519 test_errors(&SAMPLE_ED25519_KEY); -#endif #ifdef HAVE_ED448 test_errors(&SAMPLE_ED448_KEY); #endif diff --git a/tests/libdnssec/test_sign.c b/tests/libdnssec/test_sign.c index bdb19fb..933206f 100644 --- a/tests/libdnssec/test_sign.c +++ b/tests/libdnssec/test_sign.c @@ -57,7 +57,6 @@ static const dnssec_binary_t signed_ecdsa = { .size = 64, .data = (uint8_t []) { 0xad, 0x2f, }}; -#ifdef HAVE_ED25519 static const dnssec_binary_t signed_ed25519 = { .size = 64, .data = (uint8_t []) { 0x0a, 0x9e, 0x51, 0x5f, 0x16, 0x89, 0x49, 0x27, 0x0e, 0x98, 0x34, 0xd3, 0x48, 0xef, 0x5a, 0x6e, @@ -67,8 +66,7 @@ static const dnssec_binary_t signed_ed25519 = { .size = 64, .data = (uint8_t []) 0x1d, 0x08, 0x10, 0x20, 0x1c, 0x01, 0x77, 0x1b, 0x5a, 0x48, 0xd6, 0xe5, 0x1c, 0xf9, 0xe3, 0xe0, 0x70, 0x34, 0x5e, 0x02, 0x49, 0xfb, 0x9e, 0x05, - }}; -#endif +}}; #ifdef HAVE_ED448 static const dnssec_binary_t signed_ed448 = { .size = 114, .data = (uint8_t []) { @@ -82,7 +80,7 @@ static const dnssec_binary_t signed_ed448 = { .size = 114, .data = (uint8_t []) 0xe9, 0xb9, 0x76, 0xb8, 0xa6, 0xa9, 0x0a, 0x4f, 0x18, 0xe1, 0x62, 0x27, 0x74, 0x99, 0x01, 0x98, 0x5f, 0xdb, 0xea, 0xdf, 0xab, 0x59, 0x6c, 0x79, 0xe2, 0xc2, 0x2a, 0x91, 0x29, 0x00 - }}; +}}; #endif static dnssec_binary_t binary_set_string(char *str) @@ -188,10 +186,8 @@ int main(void) check_key(&SAMPLE_RSA_KEY, &input_data, &signed_rsa, true); diag("ECDSA signing"); check_key(&SAMPLE_ECDSA_KEY, &input_data, &signed_ecdsa, false); -#ifdef HAVE_ED25519 diag("ED25519 signing"); check_key(&SAMPLE_ED25519_KEY, &input_data, &signed_ed25519, true); -#endif #ifdef HAVE_ED448 diag("ED448 signing"); check_key(&SAMPLE_ED448_KEY, &input_data, &signed_ed448, true); diff --git a/tests/libknot/test_control.c b/tests/libknot/test_control.c index 3846f31..3467be4 100644 --- a/tests/libknot/test_control.c +++ b/tests/libknot/test_control.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -109,7 +109,7 @@ static void ctl_server(const char *socket, size_t argc, knot_ctl_data_t *argv) knot_ctl_t *ctl = knot_ctl_alloc(); ok(ctl != NULL, "Allocate control"); - int ret = knot_ctl_bind(ctl, socket); + int ret = knot_ctl_bind(ctl, socket, 5); is_int(KNOT_EOK, ret, "Bind control socket"); ret = knot_ctl_accept(ctl); diff --git a/tests/libknot/test_xdp_tcp.c b/tests/libknot/test_xdp_tcp.c index 7f3b994..4e02f57 100644 --- a/tests/libknot/test_xdp_tcp.c +++ b/tests/libknot/test_xdp_tcp.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -213,7 +213,7 @@ void test_syn(void) knot_xdp_msg_t msg; knot_tcp_relay_t rl = { 0 }; prepare_msg(&msg, KNOT_XDP_MSG_SYN, 1, 2); - int ret = knot_tcp_recv(&rl, &msg, 1, test_table, test_syn_table, XDP_TCP_IGNORE_NONE); + int ret = knot_tcp_recv(&rl, &msg, test_table, test_syn_table, XDP_TCP_IGNORE_NONE); is_int(KNOT_EOK, ret, "SYN: relay OK"); ret = knot_tcp_send(test_sock, &rl, 1, 1); is_int(KNOT_EOK, ret, "SYN: send OK"); @@ -241,7 +241,7 @@ void test_syn_ack_no(void) knot_xdp_msg_t msg; knot_tcp_relay_t rl = { 0 }; prepare_msg(&msg, KNOT_XDP_MSG_SYN | KNOT_XDP_MSG_ACK, 1, 2); - int ret = knot_tcp_recv(&rl, &msg, 1, test_table, test_syn_table, XDP_TCP_IGNORE_NONE); + int ret = knot_tcp_recv(&rl, &msg, test_table, test_syn_table, XDP_TCP_IGNORE_NONE); is_int(KNOT_EOK, ret, "SYN+ACK deny: relay OK"); is_int(XDP_TCP_NOOP, rl.auto_answer, "SYN+ACK deny: no auto answer"); is_int(XDP_TCP_NOOP, rl.answer, "SYN+ACK deny: no answer"); @@ -256,7 +256,7 @@ void test_establish(void) knot_tcp_relay_t rl = { 0 }; prepare_msg(&msg, KNOT_XDP_MSG_ACK, 1, 2); prepare_seqack(&msg, 0, 1); - int ret = knot_tcp_recv(&rl, &msg, 1, test_table, test_syn_table, XDP_TCP_IGNORE_NONE); + int ret = knot_tcp_recv(&rl, &msg, test_table, test_syn_table, XDP_TCP_IGNORE_NONE); is_int(KNOT_EOK, ret, "establish: relay OK"); is_int(0, test_syn_table->usage, "SYN: no connection in SYN table"); is_int(1, test_table->usage, "SYN: one connection in normal table"); @@ -274,7 +274,7 @@ void test_syn_ack(void) knot_xdp_msg_t msg; knot_tcp_relay_t rl = { 0 }; prepare_msg(&msg, KNOT_XDP_MSG_SYN | KNOT_XDP_MSG_ACK, 1000, 2000); - int ret = knot_tcp_recv(&rl, &msg, 1, test_table, NULL, XDP_TCP_IGNORE_NONE); + int ret = knot_tcp_recv(&rl, &msg, test_table, NULL, XDP_TCP_IGNORE_NONE); is_int(KNOT_EOK, ret, "SYN+ACK: relay OK"); ret = knot_tcp_send(test_sock, &rl, 1, 1); is_int(KNOT_EOK, ret, "SYN+ACK: send OK"); @@ -315,7 +315,10 @@ void test_data_fragments(void) prepare_data(&msgs[3], "\x02""AB""\xff\xff""abcdefghijklmnopqrstuvwxyz...", 34); assert(test_table); - int ret = knot_tcp_recv(rls, msgs, CONNS, test_table, test_syn_table, XDP_TCP_IGNORE_NONE); + int ret = KNOT_EOK; + for (int i = 0; i < CONNS && ret == KNOT_EOK; i++) { + ret = knot_tcp_recv(&rls[i], &msgs[i], test_table, test_syn_table, XDP_TCP_IGNORE_NONE); + } is_int(KNOT_EOK, ret, "fragments: relay OK"); assert(test_sock); ret = knot_tcp_send(test_sock, rls, CONNS, CONNS); @@ -374,7 +377,7 @@ void test_close(void) knot_xdp_msg_t wrong = msg; wrong.seqno += INT32_MAX; wrong.ackno += INT32_MAX; - int ret = knot_tcp_recv(&rl, &wrong, 1, test_table, test_syn_table, XDP_TCP_IGNORE_NONE); + int ret = knot_tcp_recv(&rl, &wrong, test_table, test_syn_table, XDP_TCP_IGNORE_NONE); is_int(KNOT_EOK, ret, "close: relay 0 OK"); is_int(KNOT_XDP_MSG_RST, rl.auto_answer, "close: reset wrong ackno"); is_int(rl.auto_seqno, wrong.ackno, "close: reset seqno"); @@ -383,7 +386,7 @@ void test_close(void) check_sent(0, 1, 0, 0); is_int(sent_seqno, wrong.ackno, "close: reset seqno sent"); - ret = knot_tcp_recv(&rl, &msg, 1, test_table, test_syn_table, XDP_TCP_IGNORE_NONE); + ret = knot_tcp_recv(&rl, &msg, test_table, test_syn_table, XDP_TCP_IGNORE_NONE); is_int(KNOT_EOK, ret, "close: relay 1 OK"); ret = knot_tcp_send(test_sock, &rl, 1, 1); is_int(KNOT_EOK, ret, "close: send OK"); @@ -395,7 +398,7 @@ void test_close(void) msg.flags &= ~KNOT_XDP_MSG_FIN; prepare_seqack(&msg, 0, 0); - ret = knot_tcp_recv(&rl, &msg, 1, test_table, test_syn_table, XDP_TCP_IGNORE_NONE); + ret = knot_tcp_recv(&rl, &msg, test_table, test_syn_table, XDP_TCP_IGNORE_NONE); is_int(KNOT_EOK, ret, "close: relay 2 OK"); ret = knot_tcp_send(test_sock, &rl, 1, 1); is_int(KNOT_EOK, ret, "close: send 2 OK"); @@ -418,7 +421,10 @@ void test_many(void) } knot_tcp_relay_t *rls = malloc(CONNS * sizeof(*rls)); - int ret = knot_tcp_recv(rls, msgs, CONNS, test_table, NULL, XDP_TCP_IGNORE_NONE); + int ret = KNOT_EOK; + for (int i = 0; i < CONNS && ret == KNOT_EOK; i++) { + ret = knot_tcp_recv(&rls[i], &msgs[i], test_table, NULL, XDP_TCP_IGNORE_NONE); + } is_int(KNOT_EOK, ret, "many: relay OK"); ret = knot_tcp_send(test_sock, rls, CONNS, CONNS); is_int(KNOT_EOK, ret, "many: relay send OK"); @@ -435,7 +441,7 @@ void test_many(void) fix_seqack(survive); prepare_data(survive, "\x00\x00", 2); assert(test_table); - ret = knot_tcp_recv(&surv_rl, survive, 1, test_table, NULL, XDP_TCP_IGNORE_NONE); + ret = knot_tcp_recv(&surv_rl, survive, test_table, NULL, XDP_TCP_IGNORE_NONE); is_int(KNOT_EOK, ret, "many/survivor: OK"); clean_sent(); @@ -479,7 +485,10 @@ void test_ibufs_size(void) for (int i = 0; i < CONNS; i++) { prepare_msg(&msgs[i], KNOT_XDP_MSG_SYN, i + 2000, 1); } - int ret = knot_tcp_recv(rls, msgs, CONNS, test_table, test_syn_table, XDP_TCP_IGNORE_NONE); + int ret = KNOT_EOK; + for (int i = 0; i < CONNS && ret == KNOT_EOK; i++) { + ret = knot_tcp_recv(&rls[i], &msgs[i], test_table, test_syn_table, XDP_TCP_IGNORE_NONE); + } is_int(KNOT_EOK, ret, "ibufs: open OK"); ret = knot_tcp_send(test_sock, rls, CONNS, CONNS); is_int(KNOT_EOK, ret, "ibufs: first send OK"); @@ -488,14 +497,16 @@ void test_ibufs_size(void) msgs[i].flags = KNOT_XDP_MSG_TCP | KNOT_XDP_MSG_ACK; } fix_seqacks(msgs, CONNS); - (void)knot_tcp_recv(rls, msgs, CONNS, test_table, test_syn_table, XDP_TCP_IGNORE_NONE); + for (int i = 0; i < CONNS && ret == KNOT_EOK; i++) { + ret = knot_tcp_recv(&rls[i], &msgs[i], test_table, test_syn_table, XDP_TCP_IGNORE_NONE); + } is_int(0, test_table->inbufs_total, "inbufs: initial total zero"); // first connection will start a fragment buf then finish it fix_seqack(&msgs[0]); prepare_data(&msgs[0], "\x00\x0a""lorem", 7); - ret = knot_tcp_recv(&rls[0], &msgs[0], 1, test_table, test_syn_table, XDP_TCP_IGNORE_NONE); + ret = knot_tcp_recv(&rls[0], &msgs[0], test_table, test_syn_table, XDP_TCP_IGNORE_NONE); is_int(KNOT_EOK, ret, "ibufs: must be OK"); ret = knot_tcp_send(test_sock, &rls[0], 1, 1); is_int(KNOT_EOK, ret, "ibufs: must send OK"); @@ -509,7 +520,9 @@ void test_ibufs_size(void) prepare_data(&msgs[1], "\x00\xff""12345", 7); prepare_data(&msgs[2], "\xff\xff""abcde", 7); prepare_data(&msgs[3], "\xff\xff""abcde", 7); - ret = knot_tcp_recv(rls, msgs, CONNS, test_table, test_syn_table, XDP_TCP_IGNORE_NONE); + for (int i = 0; i < CONNS && ret == KNOT_EOK; i++) { + ret = knot_tcp_recv(&rls[i], &msgs[i], test_table, test_syn_table, XDP_TCP_IGNORE_NONE); + } is_int(KNOT_EOK, ret, "inbufs: relay OK"); ret = knot_tcp_send(test_sock, rls, CONNS, CONNS); is_int(KNOT_EOK, ret, "inbufs: send OK"); @@ -546,11 +559,11 @@ void test_obufs(void) knot_tcp_relay_t rl = { 0 }; prepare_msg(&msg, KNOT_XDP_MSG_SYN, 1, 2); - (void)knot_tcp_recv(&rl, &msg, 1, test_table, test_syn_table, XDP_TCP_IGNORE_NONE); // SYN + (void)knot_tcp_recv(&rl, &msg, test_table, test_syn_table, XDP_TCP_IGNORE_NONE); // SYN (void)knot_tcp_send(test_sock, &rl, 1, 1); // SYN+ACK prepare_msg(&msg, KNOT_XDP_MSG_ACK, 1, 2); prepare_seqack(&msg, 0, 1); - (void)knot_tcp_recv(&rl, &msg, 1, test_table, test_syn_table, XDP_TCP_IGNORE_NONE); // ACK + (void)knot_tcp_recv(&rl, &msg, test_table, test_syn_table, XDP_TCP_IGNORE_NONE); // ACK size_t TEST_MSS = 1111; size_t DATA_LEN = 65535; // with 2-byte len prefix, this is > 64k == window_size @@ -588,7 +601,7 @@ void test_obufs(void) memset(&rl, 0, sizeof(rl)); prepare_seqack(&msg, 0, TEST_MSS); - ret = knot_tcp_recv(&rl, &msg, 1, test_table, test_syn_table, XDP_TCP_IGNORE_NONE); + ret = knot_tcp_recv(&rl, &msg, test_table, test_syn_table, XDP_TCP_IGNORE_NONE); is_int(KNOT_EOK, ret, "obufs: ACKed data"); assert(rl.conn); rl.conn->window_size = 65536; diff --git a/tests/libknot/test_yptrafo.c b/tests/libknot/test_yptrafo.c index cd26632..d76dbc4 100644 --- a/tests/libknot/test_yptrafo.c +++ b/tests/libknot/test_yptrafo.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -326,7 +326,10 @@ int main(int argc, char *argv[]) int_test("11s", 11LL * 1, YP_STIME, min, max); int_test("11m", 11LL * 60, YP_STIME, min, max); int_test("11h", 11LL * 3600, YP_STIME, min, max); - int_test("11d", 11LL * 24 * 3600, YP_STIME, min, max); + int_test("6d", 6LL * 24 * 3600, YP_STIME, min, max); + int_test("4w", 4LL * 7 * 24 * 3600, YP_STIME, min, max); + int_test("11M", 11LL * 30 * 24 * 3600, YP_STIME, min, max); + int_test("2y", 2LL * 365 * 24 * 3600, YP_STIME, min, max); int_test("1025B", 1025LL, YP_SSIZE, min, max); int_test("61s", 61LL, YP_STIME, min, max); int_bad_test("20000000001", KNOT_ERANGE, YP_SNONE, min, max); diff --git a/tests/modules/test_rrl.c b/tests/modules/test_rrl.c index 6a5210f..448ff9a 100644 --- a/tests/modules/test_rrl.c +++ b/tests/modules/test_rrl.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -15,164 +15,404 @@ */ #include <tap/basic.h> +#include <pthread.h> +#include <sched.h> +#include <stdio.h> +#include <stdatomic.h> #include "libdnssec/crypto.h" #include "libdnssec/random.h" #include "libknot/libknot.h" +#include "contrib/openbsd/siphash.h" #include "contrib/sockaddr.h" + +#include "time.h" +int fakeclock_gettime(clockid_t clockid, struct timespec *tp); +#define clock_gettime fakeclock_gettime #include "knot/modules/rrl/functions.c" -#include "stdio.h" - -/* Enable time-dependent tests. */ -//#define ENABLE_TIMED_TESTS -#define RRL_SIZE 196613 -#define RRL_THREADS 8 -#define RRL_INSERTS (RRL_SIZE/(5*RRL_THREADS)) /* lf = 1/5 */ - -/* Disabled as default as it depends on random input. - * Table may be consistent even if some collision occur (and they may occur). - * Note: Disabled due to reported problems when running on VMs due to time - * flow inconsistencies. Should work alright on a host machine. - */ -#ifdef ENABLE_TIMED_TESTS -struct bucketmap { - unsigned i; - uint64_t x; +#undef clock_gettime + +#define RRL_THREADS 4 +//#define RRL_SYNC_WITH_REAL_TIME + +#define BATCH_QUERIES_LOG 3 // threads acquire queries in batches of 8 +#define HOSTS_LOG 3 // at most 6 attackers + 2 wildcard addresses for normal users +#define TICK_QUERIES_LOG 13 // at most 1024 queries per host per tick + +// Accessing RRL configuration of INSTANT/RATE limits for V4/V6 and specific prefix. +#define LIMIT(type, Vx, prefix) (RRL_MULT(Vx, prefix) * RRL_ ## type ## _LIMIT) + +#define RRL_CONFIG(Vx, name) RRL_ ## Vx ## _ ## name +#define RRL_MULT(Vx, prefix) get_mult(RRL_CONFIG(Vx, PREFIXES), RRL_CONFIG(Vx, RATE_MULT), RRL_CONFIG(Vx, PREFIXES_CNT), prefix) +static inline kru_price_t get_mult(uint8_t prefixes[], kru_price_t mults[], size_t cnt, uint8_t wanted_prefix) { + for (size_t i = 0; i < cnt; i++) + if (prefixes[i] == wanted_prefix) + return mults[i]; + assert(0); + return 0; +} + +// Macro correction depending on the table mode. +int DIFF = 0; + +// Instant limits and rate limits per msec. +#define INST(Vx, prefix) (LIMIT(INSTANT, Vx, prefix) + DIFF) +#define RATEM(Vx, prefix) (LIMIT(RATE, Vx, prefix) / 1000 + DIFF) + +// Expected range of limits for parallel test. +#define RANGE_INST(Vx, prefix) INST(Vx, prefix) - 1, INST(Vx, prefix) + RRL_THREADS - 1 +#define RANGE_RATEM(Vx, prefix) RATEM(Vx, prefix) - 1 - DIFF, RATEM(Vx, prefix) + RRL_THREADS - DIFF +#define RANGE_UNLIM(queries) queries, queries + +/* Fix seed for randomness in RLL module. Change if improbable collisions arise. (one byte) */ +#define RRL_SEED_GENERIC 1 +#define RRL_SEED_AVX2 1 + +struct kru_generic { + SIPHASH_KEY hash_key; + // ... +}; +struct kru_avx2 { + _Alignas(32) char hash_key[48]; + // ... +}; + +/* Override time in RRL module. */ +struct timespec fakeclock_start; +uint32_t fakeclock_tick = 0; + +void fakeclock_init(void) +{ + clock_gettime(CLOCK_MONOTONIC_COARSE, &fakeclock_start); + fakeclock_tick = 0; +} + +int fakeclock_gettime(clockid_t clockid, struct timespec *tp) +{ + uint32_t inc_msec = fakeclock_tick; + tp->tv_sec = fakeclock_start.tv_sec + (fakeclock_start.tv_nsec / 1000000 + inc_msec) / 1000; + tp->tv_nsec = (fakeclock_start.tv_nsec + (inc_msec % 1000) * 1000000) % 1000000000; + return 0; +} + +struct host { + uint32_t queries_per_tick; + int addr_family; + char *addr_format; + uint32_t min_passed, max_passed; + _Atomic uint32_t passed; +}; + +struct stage { + uint32_t first_tick, last_tick; + struct host hosts[1 << HOSTS_LOG]; }; -/*! \brief Unit runnable. */ struct runnable_data { - int passed; rrl_table_t *rrl; - struct sockaddr_storage *addr; - rrl_req_t *rq; - knot_dname_t *zone; + int prime; + _Atomic uint32_t *queries_acquired, *queries_done; + struct stage *stages; }; -static void* rrl_runnable(void *arg) +static void *rrl_runnable(void *arg) { struct runnable_data *d = (struct runnable_data *)arg; + size_t si = 0; + + char addr_str[40]; struct sockaddr_storage addr; - memcpy(&addr, d->addr, sizeof(struct sockaddr_storage)); - int lock = -1; - uint32_t now = time(NULL); - struct bucketmap *m = malloc(RRL_INSERTS * sizeof(struct bucketmap)); - for (unsigned i = 0; i < RRL_INSERTS; ++i) { - m[i].i = dnssec_random_uint32_t(); - ((struct sockaddr_in *) &addr)->sin_addr.s_addr = m[i].i; - rrl_item_t *b = rrl_hash(d->rrl, &addr, d->rq, d->zone, now, &lock); - rrl_unlock(d->rrl, lock); - m[i].x = b->netblk; + + while (true) { + uint32_t qi1 = atomic_fetch_add(d->queries_acquired, 1 << BATCH_QUERIES_LOG); + + /* increment time if needed; sync on incrementing using spinlock */ + uint32_t tick = qi1 >> TICK_QUERIES_LOG; + for (size_t i = 1; tick != fakeclock_tick; i++) { + if ((*d->queries_done >> TICK_QUERIES_LOG) >= tick) { + fakeclock_tick = tick; + } + if (i % (1<<14) == 0) sched_yield(); + __sync_synchronize(); + } + + /* increment stage if needed */ + while (tick > d->stages[si].last_tick) { + ++si; + if (!d->stages[si].first_tick) return NULL; + } + +#ifdef RRL_SYNC_WITH_REAL_TIME + { + struct timespec ts_fake, ts_real; + do { + fakeclock_gettime(CLOCK_MONOTONIC_COARSE, &ts_fake); + clock_gettime(CLOCK_MONOTONIC_COARSE, &ts_real); + } while (!((ts_real.tv_sec > ts_fake.tv_sec) || + ((ts_real.tv_sec == ts_fake.tv_sec) && (ts_real.tv_nsec >= ts_fake.tv_nsec)))); + } +#endif + + if (tick >= d->stages[si].first_tick) { + uint32_t qi2 = 0; + do { + uint32_t qi = qi1 + qi2; + + /* perform query qi */ + uint32_t hi = qi % (1 << HOSTS_LOG); + if (!d->stages[si].hosts[hi].queries_per_tick) continue; + uint32_t hqi = (qi % (1 << TICK_QUERIES_LOG)) >> HOSTS_LOG; // host query index within tick + if (hqi >= d->stages[si].hosts[hi].queries_per_tick) continue; + hqi += (qi >> TICK_QUERIES_LOG) * d->stages[si].hosts[hi].queries_per_tick; // across ticks + (void)snprintf(addr_str, sizeof(addr_str), d->stages[si].hosts[hi].addr_format, + hqi % 0xff, (hqi >> 8) % 0xff, (hqi >> 16) % 0xff); + sockaddr_set(&addr, d->stages[si].hosts[hi].addr_family, addr_str, 0); + + if (rrl_query(d->rrl, &addr, NULL) == KNOT_EOK) { + atomic_fetch_add(&d->stages[si].hosts[hi].passed, 1); + if (!d->rrl->rw_mode) { + rrl_update(d->rrl, &addr, 1); + } + } + + } while ((qi2 = (qi2 + d->prime) % (1 << BATCH_QUERIES_LOG))); + } + atomic_fetch_add(d->queries_done, 1 << BATCH_QUERIES_LOG); } - for (unsigned i = 0; i < RRL_INSERTS; ++i) { - ((struct sockaddr_in *) &addr)->sin_addr.s_addr = m[i].i; - rrl_item_t *b = rrl_hash(d->rrl, &addr, d->rq, d->zone, now, &lock); - rrl_unlock(d->rrl, lock); - if (b->netblk != m[i].x) { - d->passed = 0; +} + +char *impl_name = ""; +rrl_table_t *rrl = NULL; + +void count_test(char *desc, int expected_passing, double margin_fract, + int addr_family, char *addr_format, uint32_t min_value, uint32_t max_value) +{ + uint32_t max_queries = expected_passing > 0 ? 2 * expected_passing : -expected_passing; + struct sockaddr_storage addr; + char addr_str[40]; + int cnt = -1; + + for (size_t i = 0; i < max_queries; i++) { + (void)snprintf(addr_str, sizeof(addr_str), addr_format, + i % (max_value - min_value + 1) + min_value, + i / (max_value - min_value + 1) % 256); + sockaddr_set(&addr, addr_family, addr_str, 0); + if (rrl_query(rrl, &addr, NULL) != KNOT_EOK) { + cnt = i; + break; } + if (!rrl->rw_mode) { + rrl_update(rrl, &addr, 1); + } + } + + if (expected_passing < 0) expected_passing = -1; + if (margin_fract == 0) { + is_int(expected_passing, cnt, "rrl(%s): %-48s [%7d ]", impl_name, desc, expected_passing); + } else { + int max_diff = expected_passing * margin_fract; + ok((expected_passing - max_diff <= cnt) && (cnt <= expected_passing + max_diff), + "rrl(%s): %-48s [%7d <=%7d <=%7d ]", impl_name, desc, + expected_passing - max_diff, cnt, expected_passing + max_diff); } - free(m); - return NULL; } -static void rrl_hopscotch(struct runnable_data* rd) +void test_rrl(bool rw_mode) { - rd->passed = 1; + size_t RRL_TABLE_SIZE = (1 << 20); + uint32_t RRL_INSTANT_LIMIT = (1 << 7); + uint32_t RRL_RATE_LIMIT = (1 << 16); + if (rw_mode) { + RRL_INSTANT_LIMIT = (1 << 8); + RRL_RATE_LIMIT = (1 << 17); + } + + fakeclock_init(); + + /* create rrl table */ + rrl = rrl_create(RRL_TABLE_SIZE, RRL_INSTANT_LIMIT, RRL_RATE_LIMIT, rw_mode, 0); + ok(rrl != NULL, "rrl(%s): create", impl_name); + assert(rrl); + + if (KRU.initialize == KRU_GENERIC.initialize) { + struct kru_generic *kru = (struct kru_generic *) rrl->kru; + memset(&kru->hash_key, RRL_SEED_GENERIC, sizeof(kru->hash_key)); + } else if (KRU.initialize == KRU_AVX2.initialize) { + struct kru_avx2 *kru = (struct kru_avx2 *) rrl->kru; + memset(&kru->hash_key, RRL_SEED_AVX2, sizeof(kru->hash_key)); + } else { + assert(0); + } + + /* IPv4 multi-prefix tests */ + static_assert(RRL_V4_PREFIXES_CNT == 4, + "There are no more IPv4 limited prefixes (/32, /24, /20, /18 will be tested)."); + + count_test("IPv4 instant limit /32", INST(V4, 32), 0, + AF_INET, "128.0.0.0", 0, 0); + + count_test("IPv4 instant limit /32 not applied on /31", -1, 0, + AF_INET, "128.0.0.1", 0, 0); + + count_test("IPv4 instant limit /24", INST(V4, 24) - INST(V4, 32) - 1, 0, + AF_INET, "128.0.0.%d", 2, 255); + + count_test("IPv4 instant limit /24 not applied on /23", -1, 0, + AF_INET, "128.0.1.0", 0, 0); + + count_test("IPv4 instant limit /20", INST(V4, 20) - INST(V4, 24) - 1, 0.001, + AF_INET, "128.0.%d.%d", 2, 15); + + count_test("IPv4 instant limit /20 not applied on /19", -1, 0, + AF_INET, "128.0.16.0", 0, 0); + + count_test("IPv4 instant limit /18", INST(V4, 18) - INST(V4, 20) - 1, 0.01, + AF_INET, "128.0.%d.%d", 17, 63); + + count_test("IPv4 instant limit /18 not applied on /17", -1, 0, + AF_INET, "128.0.64.0", 0, 0); + + /* IPv6 multi-prefix tests */ + static_assert(RRL_V6_PREFIXES_CNT == 5, + "There are no more IPv6 limited prefixes (/128, /64, /56, /48, /32 will be tested)."); + + count_test("IPv6 instant limit /128, independent to IPv4", INST(V6, 128), 0, + AF_INET6, "8000::", 0, 0); + + count_test("IPv6 instant limit /128 not applied on /127", -1, 0, + AF_INET6, "8000::1", 0, 0); + + count_test("IPv6 instant limit /64", INST(V6, 64) - INST(V6, 128) - 1, 0, + AF_INET6, "8000:0:0:0:%02x%02x::", 0x01, 0xff); + + count_test("IPv6 instant limit /64 not applied on /63", -1, 0, + AF_INET6, "8000:0:0:1::", 0, 0); + + count_test("IPv6 instant limit /56", INST(V6, 56) - INST(V6, 64) - 1, rw_mode ? 0 : 0.01, + AF_INET6, "8000:0:0:00%02x:%02x00::", 0x02, 0xff); + + count_test("IPv6 instant limit /56 not applied on /55", -1, 0, + AF_INET6, "8000:0:0:0100::", 0, 0); + + count_test("IPv6 instant limit /48", INST(V6, 48) - INST(V6, 56) - 1, 0.01, + AF_INET6, "8000:0:0:%02x%02x::", 0x02, 0xff); + + count_test("IPv6 instant limit /48 not applied on /47", -1, 0, + AF_INET6, "8000:0:1::", 0, 0); + + count_test("IPv6 instant limit /32", INST(V6, 32) - INST(V6, 48) - 1, rw_mode ? 0.001 : 0, + AF_INET6, "8000:0:%02x%02x::", 0x02, 0xff); + + count_test("IPv6 instant limit /32 not applied on /31", -1, 0, + AF_INET6, "8000:1::", 0, 0); + + /* limit after 1 msec */ + fakeclock_tick++; + + count_test("IPv4 rate limit /32 after 1 msec", RATEM(V4, 32), 0, + AF_INET, "128.0.0.0", 0, 0); + + count_test("IPv6 rate limit /128 after 1 msec", RATEM(V6, 128), 0, + AF_INET6, "8000::", 0, 0); + + /* parallel tests */ + struct stage stages[] = { + /* first tick, last tick, hosts */ + {32, 32, { + /* queries per tick, family, address, min passed, max passed */ + {1024, AF_INET, "%d.%d.%d.1", RANGE_UNLIM ( 1024 )}, + {1024, AF_INET, "3.3.3.3", RANGE_INST ( V4, 32 )}, + { 512, AF_INET, "4.4.4.4", RANGE_INST ( V4, 32 )}, + {1024, AF_INET6, "%x%x:%x00::1", RANGE_UNLIM ( 1024 )}, + {1024, AF_INET6, "3333::3333", RANGE_INST ( V6, 128 )}, + { 512, AF_INET6, "4444::4444", RANGE_INST ( V6, 128 )} + }}, + {33, 255, { + {1024, AF_INET, "%d.%d.%d.1", RANGE_UNLIM ( 1024 )}, + {1024, AF_INET, "3.3.3.3", RANGE_RATEM ( V4, 32 )}, + { 512, AF_INET, "4.4.4.4", RANGE_RATEM ( V4, 32 )}, + {1024, AF_INET6, "%x%x:%x00::1", RANGE_UNLIM ( 1024 )}, + {1024, AF_INET6, "3333::3333", RANGE_RATEM ( V6, 128 )}, + { 512, AF_INET6, "4444::4444", RANGE_RATEM ( V6, 128 )}, + }}, + {256, 511, { + {1024, AF_INET, "3.3.3.3", RANGE_RATEM ( V4, 32 )}, + {1024, AF_INET6, "3333::3333", RANGE_RATEM ( V6, 128 )} + }}, + {512, 512, { + {1024, AF_INET, "%d.%d.%d.1", RANGE_UNLIM ( 1024 )}, + {1024, AF_INET, "3.3.3.3", RANGE_RATEM ( V4, 32 )}, + { 512, AF_INET, "4.4.4.4", RANGE_INST ( V4, 32 )}, + {1024, AF_INET6, "%x%x:%x00::1", RANGE_UNLIM ( 1024 )}, + {1024, AF_INET6, "3333::3333", RANGE_RATEM ( V6, 128 )}, + { 512, AF_INET6, "4444::4444", RANGE_INST ( V6, 128 )} + }}, + {0} + }; + pthread_t thr[RRL_THREADS]; + struct runnable_data rd[RRL_THREADS]; + _Atomic uint32_t queries_acquired = 0, queries_done = 0; + int primes[] = {3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61}; + assert(sizeof(primes)/sizeof(*primes) >= RRL_THREADS); + for (unsigned i = 0; i < RRL_THREADS; ++i) { - pthread_create(thr + i, NULL, &rrl_runnable, rd); + rd[i].rrl = rrl; + rd[i].queries_acquired = &queries_acquired; + rd[i].queries_done = &queries_done; + rd[i].prime = primes[i]; + rd[i].stages = stages; + pthread_create(thr + i, NULL, &rrl_runnable, rd + i); } for (unsigned i = 0; i < RRL_THREADS; ++i) { pthread_join(thr[i], NULL); } -} -#endif -int main(int argc, char *argv[]) -{ - plan_lazy(); + unsigned si = 0; + do { + struct host * const h = stages[si].hosts; + uint32_t ticks = stages[si].last_tick - stages[si].first_tick + 1; + for (size_t i = 0; h[i].queries_per_tick; i++) { + ok( h[i].min_passed * ticks <= h[i].passed && h[i].passed <= h[i].max_passed * ticks, + "rrl(%s): parallel stage %d, addr %-25s [%7d <=%12.4f <=%7d ]", impl_name, + si, h[i].addr_format, h[i].min_passed, (double)h[i].passed / ticks, h[i].max_passed); + } + } while (stages[++si].first_tick); - dnssec_crypto_init(); + rrl_destroy(rrl); +} - /* Prepare query. */ - knot_pkt_t *query = knot_pkt_new(NULL, 512, NULL); - if (query == NULL) { - return KNOT_ERROR; /* Fatal */ +void test_rrl_mode(bool test_avx2, bool rw_mode) +{ + if (!rw_mode) { + DIFF = 1; } - knot_dname_t *qname = knot_dname_from_str_alloc("beef."); - int ret = knot_pkt_put_question(query, qname, KNOT_CLASS_IN, KNOT_RRTYPE_A); - knot_dname_free(qname, NULL); - if (ret != KNOT_EOK) { - knot_pkt_free(query); - return KNOT_ERROR; /* Fatal */ - } + KRU = KRU_GENERIC; + impl_name = "KRU_GENERIC"; + test_rrl(rw_mode); - /* Prepare response */ - uint8_t rbuf[65535]; - size_t rlen = sizeof(rbuf); - memcpy(rbuf, query->wire, query->size); - knot_wire_flags_set_qr(rbuf); + if (test_avx2) { + KRU = KRU_AVX2; + impl_name = "KRU_AVX2"; + test_rrl(rw_mode); + } else { + diag("AVX2 NOT available"); + } +} - rrl_req_t rq; - rq.wire = rbuf; - rq.len = rlen; - rq.query = query; - rq.flags = 0; +int main(int argc, char *argv[]) +{ + plan_lazy(); - /* 1. create rrl table */ - const uint32_t rate = 10; - rrl_table_t *rrl = rrl_create(RRL_SIZE, rate); - ok(rrl != NULL, "rrl: create"); + dnssec_crypto_init(); - /* 2. N unlimited requests. */ - knot_dname_t *zone = knot_dname_from_str_alloc("rrl."); + assert(KRU_GENERIC.initialize != KRU_AVX2.initialize); + bool test_avx2 = (KRU.initialize == KRU_AVX2.initialize); - struct sockaddr_storage addr; - struct sockaddr_storage addr6; - sockaddr_set(&addr, AF_INET, "1.2.3.4", 0); - sockaddr_set(&addr6, AF_INET6, "1122:3344:5566:7788::aabb", 0); - ret = 0; - for (unsigned i = 0; i < rate * RRL_CAPACITY; ++i) { - if (rrl_query(rrl, &addr, &rq, zone, NULL) != KNOT_EOK || - rrl_query(rrl, &addr6, &rq, zone, NULL) != KNOT_EOK) { - ret = KNOT_ELIMIT; - break; - } - } - is_int(0, ret, "rrl: unlimited IPv4/v6 requests"); - - /* 3. Endian-independent hash input buffer. */ - uint8_t buf[RRL_CLSBLK_MAXLEN]; - // CLS_LARGE + remote + dname wire. - uint8_t expectedv4[] = "\x10\x01\x02\x03\x00\x00\x00\x00\x00\x04""beef"; - rrl_classify(buf, sizeof(buf), &addr, &rq, qname); - is_int(0, memcmp(buf, expectedv4, sizeof(expectedv4)), "rrl: IPv4 hash input buffer"); - uint8_t expectedv6[] = "\x10\x11\x22\x33\x44\x55\x66\x77\x00\x04""beef"; - rrl_classify(buf, sizeof(buf), &addr6, &rq, qname); - is_int(0, memcmp(buf, expectedv6, sizeof(expectedv6)), "rrl: IPv6 hash input buffer"); - -#ifdef ENABLE_TIMED_TESTS - /* 5. limited request */ - ret = rrl_query(rrl, &addr, &rq, zone, NULL); - is_int(KNOT_ELIMIT, ret, "rrl: throttled IPv4 request"); - - /* 6. limited IPv6 request */ - ret = rrl_query(rrl, &addr6, &rq, zone, NULL); - is_int(KNOT_ELIMIT, ret, "rrl: throttled IPv6 request"); - - /* 8. hopscotch test */ - struct runnable_data rd = { - 1, rrl, &addr, &rq, zone - }; - rrl_hopscotch(&rd); - ok(rd.passed, "rrl: hashtable is ~ consistent"); -#endif + test_rrl_mode(test_avx2, true); + test_rrl_mode(test_avx2, false); - knot_dname_free(zone, NULL); - knot_pkt_free(query); - rrl_destroy(rrl); dnssec_crypto_cleanup(); return 0; } diff --git a/tests/tap/files.c b/tests/tap/files.c index f979d07..ac85277 100644 --- a/tests/tap/files.c +++ b/tests/tap/files.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2016 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 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 @@ -62,5 +62,5 @@ char *test_mkdtemp(void) bool test_rm_rf(const char *path) { - return remove_path(path); + return (remove_path(path, false) == KNOT_EOK); } |